From 5dcd6f1bb996836572e6920cc60760987ef8a0ba Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Wed, 17 Dec 2025 18:27:25 +0100 Subject: [PATCH 01/15] feat!: migrate api client to latest fern --- langfuse/_client/client.py | 42 +- langfuse/_client/datasets.py | 12 +- langfuse/_client/resource_manager.py | 6 +- langfuse/_task_manager/media_manager.py | 31 +- langfuse/_utils/parse_error.py | 4 +- langfuse/api/.fern/metadata.json | 10 + langfuse/api/README.md | 161 - langfuse/api/__init__.py | 813 +- langfuse/api/annotation_queues/__init__.py | 82 + langfuse/api/annotation_queues/client.py | 1109 +++ langfuse/api/annotation_queues/raw_client.py | 2288 +++++ .../api/annotation_queues/types/__init__.py | 84 + .../types/annotation_queue.py | 35 + .../annotation_queue_assignment_request.py | 23 + .../types/annotation_queue_item.py | 41 + .../types/annotation_queue_object_type.py | 7 + .../types/annotation_queue_status.py | 5 + ...te_annotation_queue_assignment_response.py | 25 + .../create_annotation_queue_item_request.py | 32 + .../types/create_annotation_queue_request.py | 27 + ...te_annotation_queue_assignment_response.py | 21 + .../delete_annotation_queue_item_response.py | 22 + .../types/paginated_annotation_queue_items.py | 24 + .../types/paginated_annotation_queues.py | 24 + .../update_annotation_queue_item_request.py | 22 + .../api/blob_storage_integrations/__init__.py | 67 + .../api/blob_storage_integrations/client.py | 451 + .../blob_storage_integrations/raw_client.py | 773 ++ .../types/__init__.py | 69 + .../types/blob_storage_export_frequency.py | 7 + .../types/blob_storage_export_mode.py | 7 + ...b_storage_integration_deletion_response.py | 21 + .../blob_storage_integration_file_type.py | 7 + .../blob_storage_integration_response.py | 65 + .../types/blob_storage_integration_type.py | 7 + .../blob_storage_integrations_response.py | 22 + ...create_blob_storage_integration_request.py | 98 + langfuse/api/client.py | 673 +- langfuse/api/comments/__init__.py | 44 + langfuse/api/comments/client.py | 407 + langfuse/api/comments/raw_client.py | 750 ++ langfuse/api/comments/types/__init__.py | 46 + .../comments/types/create_comment_request.py | 54 + .../comments/types/create_comment_response.py | 24 + .../comments/types/get_comments_response.py | 24 + langfuse/api/commons/__init__.py | 198 + langfuse/api/commons/errors/__init__.py | 56 + .../api/commons/errors/access_denied_error.py | 12 + langfuse/api/commons/errors/error.py | 12 + .../errors/method_not_allowed_error.py | 12 + .../api/commons/errors/not_found_error.py | 12 + .../api/commons/errors/unauthorized_error.py | 12 + langfuse/api/commons/types/__init__.py | 173 + langfuse/api/commons/types/base_score.py | 69 + langfuse/api/commons/types/base_score_v1.py | 61 + langfuse/api/commons/types/boolean_score.py | 34 + .../api/commons/types/boolean_score_v1.py | 34 + .../api/commons/types/categorical_score.py | 34 + .../api/commons/types/categorical_score_v1.py | 34 + langfuse/api/commons/types/comment.py | 40 + .../api/commons/types/comment_object_type.py | 7 + langfuse/api/commons/types/config_category.py | 22 + .../commons/types/create_score_value.py | 0 langfuse/api/commons/types/dataset.py | 48 + langfuse/api/commons/types/dataset_item.py | 45 + langfuse/api/commons/types/dataset_run.py | 70 + .../api/commons/types/dataset_run_item.py | 43 + .../commons/types/dataset_run_with_items.py | 27 + langfuse/api/commons/types/dataset_status.py | 5 + .../commons/types/map_value.py | 0 .../{resources => }/commons/types/model.py | 110 +- langfuse/api/commons/types/model_price.py | 21 + .../api/commons/types/model_usage_unit.py | 10 + langfuse/api/commons/types/numeric_score.py | 25 + .../api/commons/types/numeric_score_v1.py | 25 + langfuse/api/commons/types/observation.py | 151 + .../api/commons/types/observation_level.py | 7 + .../api/commons/types/observations_view.py | 97 + .../commons/types/pricing_tier.py | 65 +- .../commons/types/pricing_tier_condition.py | 61 +- .../commons/types/pricing_tier_input.py | 61 +- .../commons/types/pricing_tier_operator.py | 7 + langfuse/api/commons/types/score.py | 176 + langfuse/api/commons/types/score_config.py | 70 + langfuse/api/commons/types/score_data_type.py | 7 + langfuse/api/commons/types/score_source.py | 5 + langfuse/api/commons/types/score_v1.py | 152 + langfuse/api/commons/types/session.py | 32 + .../api/commons/types/session_with_traces.py | 23 + langfuse/api/commons/types/trace.py | 91 + .../api/commons/types/trace_with_details.py | 51 + .../commons/types/trace_with_full_details.py | 53 + langfuse/api/commons/types/usage.py | 63 + langfuse/api/core/__init__.py | 105 +- langfuse/api/core/api_error.py | 18 +- langfuse/api/core/client_wrapper.py | 37 +- langfuse/api/core/file.py | 49 +- langfuse/api/core/force_multipart.py | 18 + langfuse/api/core/http_client.py | 425 +- langfuse/api/core/http_response.py | 55 + langfuse/api/core/http_sse/__init__.py | 48 + langfuse/api/core/http_sse/_api.py | 114 + langfuse/api/core/http_sse/_decoders.py | 66 + .../http_sse/_exceptions.py} | 6 +- langfuse/api/core/http_sse/_models.py | 17 + langfuse/api/core/jsonable_encoder.py | 64 +- langfuse/api/core/pydantic_utilities.py | 296 +- langfuse/api/core/query_encoder.py | 55 +- langfuse/api/core/request_options.py | 3 + langfuse/api/core/serialization.py | 282 + langfuse/api/dataset_items/__init__.py | 52 + langfuse/api/dataset_items/client.py | 482 ++ langfuse/api/dataset_items/raw_client.py | 955 +++ langfuse/api/dataset_items/types/__init__.py | 50 + .../types/create_dataset_item_request.py | 44 + .../types/delete_dataset_item_response.py | 24 + .../types/paginated_dataset_items.py | 24 + langfuse/api/dataset_run_items/__init__.py | 43 + langfuse/api/dataset_run_items/client.py | 306 + langfuse/api/dataset_run_items/raw_client.py | 530 ++ .../api/dataset_run_items/types/__init__.py | 44 + .../types/create_dataset_run_item_request.py | 47 + .../types/paginated_dataset_run_items.py | 24 + langfuse/api/datasets/__init__.py | 55 + langfuse/api/datasets/client.py | 661 ++ langfuse/api/datasets/raw_client.py | 1368 +++ langfuse/api/datasets/types/__init__.py | 53 + .../datasets/types/create_dataset_request.py | 38 + .../types/delete_dataset_run_response.py | 21 + .../datasets/types/paginated_dataset_runs.py | 24 + .../api/datasets/types/paginated_datasets.py | 24 + langfuse/api/health/__init__.py | 44 + langfuse/api/health/client.py | 112 + langfuse/api/health/errors/__init__.py | 42 + .../errors/service_unavailable_error.py | 13 + langfuse/api/health/raw_client.py | 227 + langfuse/api/health/types/__init__.py | 40 + langfuse/api/health/types/health_response.py | 37 + langfuse/api/ingestion/__init__.py | 169 + .../api/{resources => }/ingestion/client.py | 121 +- langfuse/api/ingestion/raw_client.py | 293 + langfuse/api/ingestion/types/__init__.py | 169 + langfuse/api/ingestion/types/base_event.py | 34 + .../api/ingestion/types/create_event_body.py | 22 + .../api/ingestion/types/create_event_event.py | 23 + .../ingestion/types/create_generation_body.py | 48 + .../types/create_generation_event.py | 23 + .../types/create_observation_event.py | 23 + .../api/ingestion/types/create_span_body.py | 27 + .../api/ingestion/types/create_span_event.py | 23 + .../api/ingestion/types/ingestion_error.py | 24 + .../api/ingestion/types/ingestion_event.py | 225 + .../api/ingestion/types/ingestion_response.py | 24 + .../api/ingestion/types/ingestion_success.py | 22 + .../ingestion/types/ingestion_usage.py | 0 .../api/ingestion/types/observation_body.py | 60 + .../api/ingestion/types/observation_type.py | 19 + .../types/open_ai_completion_usage_schema.py | 33 + .../types/open_ai_response_usage_schema.py | 31 + langfuse/api/ingestion/types/open_ai_usage.py | 35 + .../types/optional_observation_body.py | 43 + langfuse/api/ingestion/types/score_body.py | 78 + langfuse/api/ingestion/types/score_event.py | 23 + langfuse/api/ingestion/types/sdk_log_body.py | 21 + langfuse/api/ingestion/types/sdk_log_event.py | 23 + langfuse/api/ingestion/types/trace_body.py | 43 + langfuse/api/ingestion/types/trace_event.py | 23 + .../api/ingestion/types/update_event_body.py | 22 + .../ingestion/types/update_generation_body.py | 48 + .../types/update_generation_event.py | 23 + .../types/update_observation_event.py | 23 + .../api/ingestion/types/update_span_body.py | 27 + .../api/ingestion/types/update_span_event.py | 23 + .../ingestion/types/usage_details.py | 0 langfuse/api/llm_connections/__init__.py | 55 + langfuse/api/llm_connections/client.py | 309 + langfuse/api/llm_connections/raw_client.py | 541 ++ .../api/llm_connections/types/__init__.py | 53 + .../api/llm_connections/types/llm_adapter.py | 15 + .../llm_connections/types/llm_connection.py | 84 + .../types/paginated_llm_connections.py | 24 + .../types/upsert_llm_connection_request.py | 76 + langfuse/api/media/__init__.py | 58 + langfuse/api/media/client.py | 425 + langfuse/api/media/raw_client.py | 739 ++ langfuse/api/media/types/__init__.py | 56 + .../api/media/types/get_media_response.py | 62 + .../types/get_media_upload_url_request.py | 58 + .../types/get_media_upload_url_response.py | 35 + .../api/media/types/media_content_type.py | 61 + langfuse/api/media/types/patch_media_body.py | 50 + langfuse/api/metrics/__init__.py | 40 + .../api/{resources => }/metrics/client.py | 115 +- langfuse/api/metrics/raw_client.py | 318 + langfuse/api/metrics/types/__init__.py | 40 + .../api/metrics/types/metrics_response.py | 26 + langfuse/api/models/__init__.py | 43 + langfuse/api/models/client.py | 523 ++ langfuse/api/models/raw_client.py | 993 +++ langfuse/api/models/types/__init__.py | 44 + .../models/types/create_model_request.py | 101 +- langfuse/api/models/types/paginated_models.py | 24 + langfuse/api/observations/__init__.py | 43 + .../{resources => }/observations/client.py | 247 +- langfuse/api/observations/raw_client.py | 755 ++ langfuse/api/observations/types/__init__.py | 44 + .../api/observations/types/observations.py | 24 + .../observations/types/observations_views.py | 24 + langfuse/api/opentelemetry/__init__.py | 67 + .../{resources => }/opentelemetry/client.py | 121 +- langfuse/api/opentelemetry/raw_client.py | 291 + langfuse/api/opentelemetry/types/__init__.py | 65 + .../api/opentelemetry/types/otel_attribute.py | 34 + .../types/otel_attribute_value.py | 53 + .../api/opentelemetry/types/otel_resource.py | 31 + .../opentelemetry/types/otel_resource_span.py | 39 + .../api/opentelemetry/types/otel_scope.py | 41 + .../opentelemetry/types/otel_scope_span.py | 35 + langfuse/api/opentelemetry/types/otel_span.py | 83 + .../types/otel_trace_response.py | 23 + langfuse/api/organizations/__init__.py | 73 + langfuse/api/organizations/client.py | 752 ++ langfuse/api/organizations/raw_client.py | 1707 ++++ langfuse/api/organizations/types/__init__.py | 71 + .../types/delete_membership_request.py | 23 + .../types/membership_deletion_response.py | 24 + .../organizations/types/membership_request.py | 25 + .../types/membership_response.py | 27 + .../organizations/types/membership_role.py | 7 + .../types/memberships_response.py | 22 + .../types/organization_api_key.py | 38 + .../types/organization_api_keys_response.py | 26 + .../types/organization_project.py | 32 + .../types/organization_projects_response.py | 22 + langfuse/api/projects/__init__.py | 64 + langfuse/api/projects/client.py | 756 ++ langfuse/api/projects/raw_client.py | 1571 ++++ langfuse/api/projects/types/__init__.py | 62 + .../types/api_key_deletion_response.py | 25 + langfuse/api/projects/types/api_key_list.py | 30 + .../api/projects/types/api_key_response.py | 37 + .../api/projects/types/api_key_summary.py | 42 + langfuse/api/projects/types/project.py | 35 + .../types/project_deletion_response.py | 22 + langfuse/api/projects/types/projects.py | 22 + .../prompt_version/__init__.py | 2 + langfuse/api/prompt_version/client.py | 157 + langfuse/api/prompt_version/raw_client.py | 264 + langfuse/api/prompts/__init__.py | 100 + langfuse/api/prompts/client.py | 530 ++ langfuse/api/prompts/raw_client.py | 977 +++ langfuse/api/prompts/types/__init__.py | 100 + langfuse/api/prompts/types/base_prompt.py | 49 + langfuse/api/prompts/types/chat_message.py | 22 + .../types/chat_message_with_placeholders.py | 50 + langfuse/api/prompts/types/chat_prompt.py | 23 + .../types/create_chat_prompt_request.py | 42 + .../prompts/types/create_prompt_request.py | 63 + .../types/create_text_prompt_request.py | 41 + .../api/prompts/types/placeholder_message.py | 21 + langfuse/api/prompts/types/prompt.py | 72 + langfuse/api/prompts/types/prompt_meta.py | 42 + .../types/prompt_meta_list_response.py | 24 + langfuse/api/prompts/types/prompt_type.py | 5 + langfuse/api/prompts/types/text_prompt.py | 22 + langfuse/api/reference.md | 7553 ----------------- langfuse/api/resources/__init__.py | 522 -- .../resources/annotation_queues/__init__.py | 33 - .../api/resources/annotation_queues/client.py | 1642 ---- .../annotation_queues/types/__init__.py | 35 - .../types/annotation_queue.py | 49 - .../annotation_queue_assignment_request.py | 44 - .../types/annotation_queue_item.py | 55 - .../types/annotation_queue_object_type.py | 25 - .../types/annotation_queue_status.py | 21 - ...te_annotation_queue_assignment_response.py | 46 - .../create_annotation_queue_item_request.py | 51 - .../types/create_annotation_queue_request.py | 46 - ...te_annotation_queue_assignment_response.py | 42 - .../delete_annotation_queue_item_response.py | 43 - .../types/paginated_annotation_queue_items.py | 45 - .../types/paginated_annotation_queues.py | 45 - .../update_annotation_queue_item_request.py | 43 - .../blob_storage_integrations/__init__.py | 23 - .../blob_storage_integrations/client.py | 492 -- .../types/__init__.py | 23 - .../types/blob_storage_export_frequency.py | 25 - .../types/blob_storage_export_mode.py | 25 - ...b_storage_integration_deletion_response.py | 42 - .../blob_storage_integration_file_type.py | 25 - .../blob_storage_integration_response.py | 75 - .../types/blob_storage_integration_type.py | 25 - .../blob_storage_integrations_response.py | 43 - ...create_blob_storage_integration_request.py | 108 - langfuse/api/resources/comments/__init__.py | 5 - langfuse/api/resources/comments/client.py | 520 -- .../api/resources/comments/types/__init__.py | 7 - .../comments/types/create_comment_request.py | 69 - .../comments/types/create_comment_response.py | 45 - .../comments/types/get_comments_response.py | 45 - langfuse/api/resources/commons/__init__.py | 111 - .../api/resources/commons/errors/__init__.py | 15 - .../commons/errors/access_denied_error.py | 10 - .../api/resources/commons/errors/error.py | 10 - .../errors/method_not_allowed_error.py | 10 - .../commons/errors/not_found_error.py | 10 - .../commons/errors/unauthorized_error.py | 10 - .../api/resources/commons/types/__init__.py | 91 - .../api/resources/commons/types/base_score.py | 79 - .../resources/commons/types/base_score_v_1.py | 73 - .../resources/commons/types/boolean_score.py | 53 - .../commons/types/boolean_score_v_1.py | 53 - .../commons/types/categorical_score.py | 53 - .../commons/types/categorical_score_v_1.py | 53 - .../api/resources/commons/types/comment.py | 54 - .../commons/types/comment_object_type.py | 29 - .../commons/types/config_category.py | 43 - .../api/resources/commons/types/dataset.py | 64 - .../resources/commons/types/dataset_item.py | 61 - .../resources/commons/types/dataset_run.py | 82 - .../commons/types/dataset_run_item.py | 53 - .../commons/types/dataset_run_with_items.py | 48 - .../resources/commons/types/dataset_status.py | 21 - .../resources/commons/types/model_price.py | 42 - .../commons/types/model_usage_unit.py | 41 - .../resources/commons/types/numeric_score.py | 48 - .../commons/types/numeric_score_v_1.py | 48 - .../resources/commons/types/observation.py | 164 - .../commons/types/observation_level.py | 29 - .../commons/types/observations_view.py | 116 - .../commons/types/pricing_tier_operator.py | 41 - langfuse/api/resources/commons/types/score.py | 207 - .../resources/commons/types/score_config.py | 82 - .../commons/types/score_data_type.py | 25 - .../resources/commons/types/score_source.py | 25 - .../api/resources/commons/types/score_v_1.py | 189 - .../api/resources/commons/types/session.py | 50 - .../commons/types/session_with_traces.py | 46 - langfuse/api/resources/commons/types/trace.py | 109 - .../commons/types/trace_with_details.py | 68 - .../commons/types/trace_with_full_details.py | 70 - langfuse/api/resources/commons/types/usage.py | 84 - .../api/resources/dataset_items/__init__.py | 13 - .../api/resources/dataset_items/client.py | 640 -- .../resources/dataset_items/types/__init__.py | 11 - .../types/create_dataset_item_request.py | 65 - .../types/delete_dataset_item_response.py | 45 - .../types/paginated_dataset_items.py | 45 - .../resources/dataset_run_items/__init__.py | 5 - .../api/resources/dataset_run_items/client.py | 366 - .../dataset_run_items/types/__init__.py | 6 - .../types/create_dataset_run_item_request.py | 64 - .../types/paginated_dataset_run_items.py | 45 - langfuse/api/resources/datasets/__init__.py | 15 - langfuse/api/resources/datasets/client.py | 942 -- .../api/resources/datasets/types/__init__.py | 13 - .../datasets/types/create_dataset_request.py | 59 - .../types/delete_dataset_run_response.py | 42 - .../datasets/types/paginated_dataset_runs.py | 45 - .../datasets/types/paginated_datasets.py | 45 - langfuse/api/resources/health/__init__.py | 6 - langfuse/api/resources/health/client.py | 154 - .../api/resources/health/errors/__init__.py | 5 - .../errors/service_unavailable_error.py | 8 - .../api/resources/health/types/__init__.py | 5 - .../resources/health/types/health_response.py | 58 - langfuse/api/resources/ingestion/__init__.py | 91 - .../api/resources/ingestion/types/__init__.py | 91 - .../resources/ingestion/types/base_event.py | 55 - .../ingestion/types/create_event_body.py | 45 - .../ingestion/types/create_event_event.py | 46 - .../ingestion/types/create_generation_body.py | 67 - .../types/create_generation_event.py | 46 - .../types/create_observation_event.py | 46 - .../ingestion/types/create_span_body.py | 47 - .../ingestion/types/create_span_event.py | 46 - .../ingestion/types/ingestion_error.py | 45 - .../ingestion/types/ingestion_event.py | 422 - .../ingestion/types/ingestion_response.py | 45 - .../ingestion/types/ingestion_success.py | 43 - .../ingestion/types/observation_body.py | 77 - .../ingestion/types/observation_type.py | 53 - .../types/open_ai_completion_usage_schema.py | 54 - .../types/open_ai_response_usage_schema.py | 52 - .../ingestion/types/open_ai_usage.py | 56 - .../types/optional_observation_body.py | 61 - .../resources/ingestion/types/score_body.py | 93 - .../resources/ingestion/types/score_event.py | 46 - .../resources/ingestion/types/sdk_log_body.py | 42 - .../ingestion/types/sdk_log_event.py | 46 - .../resources/ingestion/types/trace_body.py | 61 - .../resources/ingestion/types/trace_event.py | 46 - .../ingestion/types/update_event_body.py | 45 - .../ingestion/types/update_generation_body.py | 67 - .../types/update_generation_event.py | 46 - .../types/update_observation_event.py | 46 - .../ingestion/types/update_span_body.py | 47 - .../ingestion/types/update_span_event.py | 46 - .../api/resources/llm_connections/__init__.py | 15 - .../api/resources/llm_connections/client.py | 340 - .../llm_connections/types/__init__.py | 13 - .../llm_connections/types/llm_adapter.py | 37 - .../llm_connections/types/llm_connection.py | 92 - .../types/paginated_llm_connections.py | 45 - .../types/upsert_llm_connection_request.py | 95 - langfuse/api/resources/media/__init__.py | 17 - langfuse/api/resources/media/client.py | 505 -- .../api/resources/media/types/__init__.py | 15 - .../media/types/get_media_response.py | 72 - .../types/get_media_upload_url_request.py | 71 - .../types/get_media_upload_url_response.py | 54 - .../media/types/media_content_type.py | 231 - .../resources/media/types/patch_media_body.py | 66 - langfuse/api/resources/metrics/__init__.py | 5 - .../api/resources/metrics/types/__init__.py | 5 - .../metrics/types/metrics_response.py | 47 - langfuse/api/resources/models/__init__.py | 5 - langfuse/api/resources/models/client.py | 607 -- .../api/resources/models/types/__init__.py | 6 - .../models/types/paginated_models.py | 45 - .../api/resources/observations/__init__.py | 5 - .../resources/observations/types/__init__.py | 6 - .../observations/types/observations.py | 45 - .../observations/types/observations_views.py | 45 - .../api/resources/opentelemetry/__init__.py | 23 - .../resources/opentelemetry/types/__init__.py | 21 - .../opentelemetry/types/otel_attribute.py | 55 - .../types/otel_attribute_value.py | 72 - .../opentelemetry/types/otel_resource.py | 52 - .../opentelemetry/types/otel_resource_span.py | 60 - .../opentelemetry/types/otel_scope.py | 62 - .../opentelemetry/types/otel_scope_span.py | 56 - .../opentelemetry/types/otel_span.py | 104 - .../types/otel_trace_response.py | 44 - .../api/resources/organizations/__init__.py | 27 - .../api/resources/organizations/client.py | 1205 --- .../resources/organizations/types/__init__.py | 25 - .../types/delete_membership_request.py | 44 - .../types/membership_deletion_response.py | 45 - .../organizations/types/membership_request.py | 46 - .../types/membership_response.py | 48 - .../organizations/types/membership_role.py | 29 - .../types/memberships_response.py | 43 - .../types/organization_api_key.py | 54 - .../types/organization_api_keys_response.py | 45 - .../types/organization_project.py | 48 - .../types/organization_projects_response.py | 43 - langfuse/api/resources/projects/__init__.py | 21 - langfuse/api/resources/projects/client.py | 1106 --- .../api/resources/projects/types/__init__.py | 19 - .../types/api_key_deletion_response.py | 46 - .../resources/projects/types/api_key_list.py | 49 - .../projects/types/api_key_response.py | 53 - .../projects/types/api_key_summary.py | 58 - .../api/resources/projects/types/project.py | 56 - .../types/project_deletion_response.py | 43 - .../api/resources/projects/types/projects.py | 43 - .../api/resources/prompt_version/client.py | 199 - langfuse/api/resources/prompts/__init__.py | 45 - langfuse/api/resources/prompts/client.py | 749 -- .../api/resources/prompts/types/__init__.py | 45 - .../resources/prompts/types/base_prompt.py | 69 - .../resources/prompts/types/chat_message.py | 43 - .../types/chat_message_with_placeholders.py | 87 - .../resources/prompts/types/chat_prompt.py | 46 - .../types/create_chat_prompt_request.py | 63 - .../prompts/types/create_prompt_request.py | 103 - .../types/create_text_prompt_request.py | 62 - .../prompts/types/placeholder_message.py | 42 - .../api/resources/prompts/types/prompt.py | 111 - .../resources/prompts/types/prompt_meta.py | 58 - .../types/prompt_meta_list_response.py | 45 - .../resources/prompts/types/prompt_type.py | 19 - .../resources/prompts/types/text_prompt.py | 45 - langfuse/api/resources/scim/__init__.py | 41 - langfuse/api/resources/scim/client.py | 1042 --- langfuse/api/resources/scim/types/__init__.py | 39 - .../scim/types/authentication_scheme.py | 48 - .../api/resources/scim/types/bulk_config.py | 46 - .../resources/scim/types/empty_response.py | 44 - .../api/resources/scim/types/filter_config.py | 45 - .../api/resources/scim/types/resource_meta.py | 45 - .../api/resources/scim/types/resource_type.py | 55 - .../scim/types/resource_types_response.py | 47 - .../resources/scim/types/schema_extension.py | 45 - .../resources/scim/types/schema_resource.py | 47 - .../resources/scim/types/schemas_response.py | 47 - .../api/resources/scim/types/scim_email.py | 44 - .../scim/types/scim_feature_support.py | 42 - .../api/resources/scim/types/scim_name.py | 42 - .../api/resources/scim/types/scim_user.py | 52 - .../scim/types/scim_users_list_response.py | 49 - .../scim/types/service_provider_config.py | 60 - .../api/resources/scim/types/user_meta.py | 48 - langfuse/api/resources/score/__init__.py | 5 - langfuse/api/resources/score/client.py | 322 - .../api/resources/score/types/__init__.py | 6 - .../score/types/create_score_request.py | 97 - .../score/types/create_score_response.py | 45 - .../api/resources/score_configs/__init__.py | 5 - .../api/resources/score_configs/client.py | 632 -- .../resources/score_configs/types/__init__.py | 7 - .../types/create_score_config_request.py | 72 - .../score_configs/types/score_configs.py | 45 - .../types/update_score_config_request.py | 81 - langfuse/api/resources/score_v_2/__init__.py | 25 - .../api/resources/score_v_2/types/__init__.py | 25 - .../score_v_2/types/get_scores_response.py | 45 - .../types/get_scores_response_data.py | 215 - .../types/get_scores_response_data_boolean.py | 46 - .../get_scores_response_data_categorical.py | 46 - .../types/get_scores_response_data_numeric.py | 46 - .../types/get_scores_response_trace_data.py | 57 - langfuse/api/resources/sessions/__init__.py | 5 - langfuse/api/resources/sessions/client.py | 367 - .../api/resources/sessions/types/__init__.py | 5 - .../sessions/types/paginated_sessions.py | 45 - langfuse/api/resources/trace/__init__.py | 5 - .../api/resources/trace/types/__init__.py | 7 - .../trace/types/delete_trace_response.py | 42 - langfuse/api/resources/trace/types/sort.py | 42 - langfuse/api/resources/trace/types/traces.py | 45 - langfuse/api/resources/utils/__init__.py | 5 - .../api/resources/utils/resources/__init__.py | 6 - .../resources/pagination/types/__init__.py | 5 - .../pagination/types/meta_response.py | 62 - langfuse/api/scim/__init__.py | 94 + langfuse/api/scim/client.py | 686 ++ langfuse/api/scim/raw_client.py | 1528 ++++ langfuse/api/scim/types/__init__.py | 92 + .../api/scim/types/authentication_scheme.py | 27 + langfuse/api/scim/types/bulk_config.py | 29 + langfuse/api/scim/types/empty_response.py | 23 + langfuse/api/scim/types/filter_config.py | 24 + langfuse/api/scim/types/resource_meta.py | 24 + langfuse/api/scim/types/resource_type.py | 34 + .../api/scim/types/resource_types_response.py | 28 + langfuse/api/scim/types/schema_extension.py | 24 + langfuse/api/scim/types/schema_resource.py | 26 + langfuse/api/scim/types/schemas_response.py | 28 + langfuse/api/scim/types/scim_email.py | 23 + .../api/scim/types/scim_feature_support.py | 21 + langfuse/api/scim/types/scim_name.py | 21 + langfuse/api/scim/types/scim_user.py | 31 + .../scim/types/scim_users_list_response.py | 32 + .../api/scim/types/service_provider_config.py | 43 + langfuse/api/scim/types/user_meta.py | 27 + langfuse/api/score/__init__.py | 43 + langfuse/api/score/client.py | 329 + langfuse/api/score/raw_client.py | 545 ++ langfuse/api/score/types/__init__.py | 44 + .../api/score/types/create_score_request.py | 82 + .../api/score/types/create_score_response.py | 24 + langfuse/api/score_configs/__init__.py | 44 + langfuse/api/score_configs/client.py | 524 ++ langfuse/api/score_configs/raw_client.py | 1012 +++ langfuse/api/score_configs/types/__init__.py | 46 + .../types/create_score_config_request.py | 53 + .../api/score_configs/types/score_configs.py | 24 + .../types/update_score_config_request.py | 60 + langfuse/api/score_v2/__init__.py | 70 + langfuse/api/score_v2/client.py | 390 + .../client.py => score_v2/raw_client.py} | 413 +- langfuse/api/score_v2/types/__init__.py | 70 + .../api/score_v2/types/get_scores_response.py | 24 + .../types/get_scores_response_data.py | 184 + .../types/get_scores_response_data_boolean.py | 23 + .../get_scores_response_data_categorical.py | 23 + .../types/get_scores_response_data_numeric.py | 23 + .../types/get_scores_response_trace_data.py | 38 + langfuse/api/sessions/__init__.py | 40 + langfuse/api/sessions/client.py | 262 + langfuse/api/sessions/raw_client.py | 500 ++ langfuse/api/sessions/types/__init__.py | 40 + .../api/sessions/types/paginated_sessions.py | 24 + langfuse/api/trace/__init__.py | 44 + langfuse/api/{resources => }/trace/client.py | 399 +- langfuse/api/trace/raw_client.py | 1208 +++ langfuse/api/trace/types/__init__.py | 46 + .../api/trace/types/delete_trace_response.py | 21 + langfuse/api/trace/types/sort.py | 21 + langfuse/api/trace/types/traces.py | 24 + langfuse/api/utils/__init__.py | 44 + langfuse/api/utils/pagination/__init__.py | 40 + .../api/utils/pagination/types/__init__.py | 40 + .../utils/pagination/types/meta_response.py | 45 + langfuse/batch_evaluation.py | 2 +- langfuse/langchain/CallbackHandler.py | 4 +- langfuse/model.py | 45 +- langfuse/types.py | 5 +- pyproject.toml | 6 +- tests/test_prompt.py | 2 +- tests/utils.py | 4 +- 593 files changed, 42859 insertions(+), 33752 deletions(-) create mode 100644 langfuse/api/.fern/metadata.json delete mode 100644 langfuse/api/README.md create mode 100644 langfuse/api/annotation_queues/__init__.py create mode 100644 langfuse/api/annotation_queues/client.py create mode 100644 langfuse/api/annotation_queues/raw_client.py create mode 100644 langfuse/api/annotation_queues/types/__init__.py create mode 100644 langfuse/api/annotation_queues/types/annotation_queue.py create mode 100644 langfuse/api/annotation_queues/types/annotation_queue_assignment_request.py create mode 100644 langfuse/api/annotation_queues/types/annotation_queue_item.py create mode 100644 langfuse/api/annotation_queues/types/annotation_queue_object_type.py create mode 100644 langfuse/api/annotation_queues/types/annotation_queue_status.py create mode 100644 langfuse/api/annotation_queues/types/create_annotation_queue_assignment_response.py create mode 100644 langfuse/api/annotation_queues/types/create_annotation_queue_item_request.py create mode 100644 langfuse/api/annotation_queues/types/create_annotation_queue_request.py create mode 100644 langfuse/api/annotation_queues/types/delete_annotation_queue_assignment_response.py create mode 100644 langfuse/api/annotation_queues/types/delete_annotation_queue_item_response.py create mode 100644 langfuse/api/annotation_queues/types/paginated_annotation_queue_items.py create mode 100644 langfuse/api/annotation_queues/types/paginated_annotation_queues.py create mode 100644 langfuse/api/annotation_queues/types/update_annotation_queue_item_request.py create mode 100644 langfuse/api/blob_storage_integrations/__init__.py create mode 100644 langfuse/api/blob_storage_integrations/client.py create mode 100644 langfuse/api/blob_storage_integrations/raw_client.py create mode 100644 langfuse/api/blob_storage_integrations/types/__init__.py create mode 100644 langfuse/api/blob_storage_integrations/types/blob_storage_export_frequency.py create mode 100644 langfuse/api/blob_storage_integrations/types/blob_storage_export_mode.py create mode 100644 langfuse/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py create mode 100644 langfuse/api/blob_storage_integrations/types/blob_storage_integration_file_type.py create mode 100644 langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py create mode 100644 langfuse/api/blob_storage_integrations/types/blob_storage_integration_type.py create mode 100644 langfuse/api/blob_storage_integrations/types/blob_storage_integrations_response.py create mode 100644 langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py create mode 100644 langfuse/api/comments/__init__.py create mode 100644 langfuse/api/comments/client.py create mode 100644 langfuse/api/comments/raw_client.py create mode 100644 langfuse/api/comments/types/__init__.py create mode 100644 langfuse/api/comments/types/create_comment_request.py create mode 100644 langfuse/api/comments/types/create_comment_response.py create mode 100644 langfuse/api/comments/types/get_comments_response.py create mode 100644 langfuse/api/commons/__init__.py create mode 100644 langfuse/api/commons/errors/__init__.py create mode 100644 langfuse/api/commons/errors/access_denied_error.py create mode 100644 langfuse/api/commons/errors/error.py create mode 100644 langfuse/api/commons/errors/method_not_allowed_error.py create mode 100644 langfuse/api/commons/errors/not_found_error.py create mode 100644 langfuse/api/commons/errors/unauthorized_error.py create mode 100644 langfuse/api/commons/types/__init__.py create mode 100644 langfuse/api/commons/types/base_score.py create mode 100644 langfuse/api/commons/types/base_score_v1.py create mode 100644 langfuse/api/commons/types/boolean_score.py create mode 100644 langfuse/api/commons/types/boolean_score_v1.py create mode 100644 langfuse/api/commons/types/categorical_score.py create mode 100644 langfuse/api/commons/types/categorical_score_v1.py create mode 100644 langfuse/api/commons/types/comment.py create mode 100644 langfuse/api/commons/types/comment_object_type.py create mode 100644 langfuse/api/commons/types/config_category.py rename langfuse/api/{resources => }/commons/types/create_score_value.py (100%) create mode 100644 langfuse/api/commons/types/dataset.py create mode 100644 langfuse/api/commons/types/dataset_item.py create mode 100644 langfuse/api/commons/types/dataset_run.py create mode 100644 langfuse/api/commons/types/dataset_run_item.py create mode 100644 langfuse/api/commons/types/dataset_run_with_items.py create mode 100644 langfuse/api/commons/types/dataset_status.py rename langfuse/api/{resources => }/commons/types/map_value.py (100%) rename langfuse/api/{resources => }/commons/types/model.py (55%) create mode 100644 langfuse/api/commons/types/model_price.py create mode 100644 langfuse/api/commons/types/model_usage_unit.py create mode 100644 langfuse/api/commons/types/numeric_score.py create mode 100644 langfuse/api/commons/types/numeric_score_v1.py create mode 100644 langfuse/api/commons/types/observation.py create mode 100644 langfuse/api/commons/types/observation_level.py create mode 100644 langfuse/api/commons/types/observations_view.py rename langfuse/api/{resources => }/commons/types/pricing_tier.py (66%) rename langfuse/api/{resources => }/commons/types/pricing_tier_condition.py (57%) rename langfuse/api/{resources => }/commons/types/pricing_tier_input.py (59%) create mode 100644 langfuse/api/commons/types/pricing_tier_operator.py create mode 100644 langfuse/api/commons/types/score.py create mode 100644 langfuse/api/commons/types/score_config.py create mode 100644 langfuse/api/commons/types/score_data_type.py create mode 100644 langfuse/api/commons/types/score_source.py create mode 100644 langfuse/api/commons/types/score_v1.py create mode 100644 langfuse/api/commons/types/session.py create mode 100644 langfuse/api/commons/types/session_with_traces.py create mode 100644 langfuse/api/commons/types/trace.py create mode 100644 langfuse/api/commons/types/trace_with_details.py create mode 100644 langfuse/api/commons/types/trace_with_full_details.py create mode 100644 langfuse/api/commons/types/usage.py create mode 100644 langfuse/api/core/force_multipart.py create mode 100644 langfuse/api/core/http_response.py create mode 100644 langfuse/api/core/http_sse/__init__.py create mode 100644 langfuse/api/core/http_sse/_api.py create mode 100644 langfuse/api/core/http_sse/_decoders.py rename langfuse/api/{resources/utils/resources/pagination/__init__.py => core/http_sse/_exceptions.py} (51%) create mode 100644 langfuse/api/core/http_sse/_models.py create mode 100644 langfuse/api/core/serialization.py create mode 100644 langfuse/api/dataset_items/__init__.py create mode 100644 langfuse/api/dataset_items/client.py create mode 100644 langfuse/api/dataset_items/raw_client.py create mode 100644 langfuse/api/dataset_items/types/__init__.py create mode 100644 langfuse/api/dataset_items/types/create_dataset_item_request.py create mode 100644 langfuse/api/dataset_items/types/delete_dataset_item_response.py create mode 100644 langfuse/api/dataset_items/types/paginated_dataset_items.py create mode 100644 langfuse/api/dataset_run_items/__init__.py create mode 100644 langfuse/api/dataset_run_items/client.py create mode 100644 langfuse/api/dataset_run_items/raw_client.py create mode 100644 langfuse/api/dataset_run_items/types/__init__.py create mode 100644 langfuse/api/dataset_run_items/types/create_dataset_run_item_request.py create mode 100644 langfuse/api/dataset_run_items/types/paginated_dataset_run_items.py create mode 100644 langfuse/api/datasets/__init__.py create mode 100644 langfuse/api/datasets/client.py create mode 100644 langfuse/api/datasets/raw_client.py create mode 100644 langfuse/api/datasets/types/__init__.py create mode 100644 langfuse/api/datasets/types/create_dataset_request.py create mode 100644 langfuse/api/datasets/types/delete_dataset_run_response.py create mode 100644 langfuse/api/datasets/types/paginated_dataset_runs.py create mode 100644 langfuse/api/datasets/types/paginated_datasets.py create mode 100644 langfuse/api/health/__init__.py create mode 100644 langfuse/api/health/client.py create mode 100644 langfuse/api/health/errors/__init__.py create mode 100644 langfuse/api/health/errors/service_unavailable_error.py create mode 100644 langfuse/api/health/raw_client.py create mode 100644 langfuse/api/health/types/__init__.py create mode 100644 langfuse/api/health/types/health_response.py create mode 100644 langfuse/api/ingestion/__init__.py rename langfuse/api/{resources => }/ingestion/client.py (64%) create mode 100644 langfuse/api/ingestion/raw_client.py create mode 100644 langfuse/api/ingestion/types/__init__.py create mode 100644 langfuse/api/ingestion/types/base_event.py create mode 100644 langfuse/api/ingestion/types/create_event_body.py create mode 100644 langfuse/api/ingestion/types/create_event_event.py create mode 100644 langfuse/api/ingestion/types/create_generation_body.py create mode 100644 langfuse/api/ingestion/types/create_generation_event.py create mode 100644 langfuse/api/ingestion/types/create_observation_event.py create mode 100644 langfuse/api/ingestion/types/create_span_body.py create mode 100644 langfuse/api/ingestion/types/create_span_event.py create mode 100644 langfuse/api/ingestion/types/ingestion_error.py create mode 100644 langfuse/api/ingestion/types/ingestion_event.py create mode 100644 langfuse/api/ingestion/types/ingestion_response.py create mode 100644 langfuse/api/ingestion/types/ingestion_success.py rename langfuse/api/{resources => }/ingestion/types/ingestion_usage.py (100%) create mode 100644 langfuse/api/ingestion/types/observation_body.py create mode 100644 langfuse/api/ingestion/types/observation_type.py create mode 100644 langfuse/api/ingestion/types/open_ai_completion_usage_schema.py create mode 100644 langfuse/api/ingestion/types/open_ai_response_usage_schema.py create mode 100644 langfuse/api/ingestion/types/open_ai_usage.py create mode 100644 langfuse/api/ingestion/types/optional_observation_body.py create mode 100644 langfuse/api/ingestion/types/score_body.py create mode 100644 langfuse/api/ingestion/types/score_event.py create mode 100644 langfuse/api/ingestion/types/sdk_log_body.py create mode 100644 langfuse/api/ingestion/types/sdk_log_event.py create mode 100644 langfuse/api/ingestion/types/trace_body.py create mode 100644 langfuse/api/ingestion/types/trace_event.py create mode 100644 langfuse/api/ingestion/types/update_event_body.py create mode 100644 langfuse/api/ingestion/types/update_generation_body.py create mode 100644 langfuse/api/ingestion/types/update_generation_event.py create mode 100644 langfuse/api/ingestion/types/update_observation_event.py create mode 100644 langfuse/api/ingestion/types/update_span_body.py create mode 100644 langfuse/api/ingestion/types/update_span_event.py rename langfuse/api/{resources => }/ingestion/types/usage_details.py (100%) create mode 100644 langfuse/api/llm_connections/__init__.py create mode 100644 langfuse/api/llm_connections/client.py create mode 100644 langfuse/api/llm_connections/raw_client.py create mode 100644 langfuse/api/llm_connections/types/__init__.py create mode 100644 langfuse/api/llm_connections/types/llm_adapter.py create mode 100644 langfuse/api/llm_connections/types/llm_connection.py create mode 100644 langfuse/api/llm_connections/types/paginated_llm_connections.py create mode 100644 langfuse/api/llm_connections/types/upsert_llm_connection_request.py create mode 100644 langfuse/api/media/__init__.py create mode 100644 langfuse/api/media/client.py create mode 100644 langfuse/api/media/raw_client.py create mode 100644 langfuse/api/media/types/__init__.py create mode 100644 langfuse/api/media/types/get_media_response.py create mode 100644 langfuse/api/media/types/get_media_upload_url_request.py create mode 100644 langfuse/api/media/types/get_media_upload_url_response.py create mode 100644 langfuse/api/media/types/media_content_type.py create mode 100644 langfuse/api/media/types/patch_media_body.py create mode 100644 langfuse/api/metrics/__init__.py rename langfuse/api/{resources => }/metrics/client.py (64%) create mode 100644 langfuse/api/metrics/raw_client.py create mode 100644 langfuse/api/metrics/types/__init__.py create mode 100644 langfuse/api/metrics/types/metrics_response.py create mode 100644 langfuse/api/models/__init__.py create mode 100644 langfuse/api/models/client.py create mode 100644 langfuse/api/models/raw_client.py create mode 100644 langfuse/api/models/types/__init__.py rename langfuse/api/{resources => }/models/types/create_model_request.py (53%) create mode 100644 langfuse/api/models/types/paginated_models.py create mode 100644 langfuse/api/observations/__init__.py rename langfuse/api/{resources => }/observations/client.py (67%) create mode 100644 langfuse/api/observations/raw_client.py create mode 100644 langfuse/api/observations/types/__init__.py create mode 100644 langfuse/api/observations/types/observations.py create mode 100644 langfuse/api/observations/types/observations_views.py create mode 100644 langfuse/api/opentelemetry/__init__.py rename langfuse/api/{resources => }/opentelemetry/client.py (69%) create mode 100644 langfuse/api/opentelemetry/raw_client.py create mode 100644 langfuse/api/opentelemetry/types/__init__.py create mode 100644 langfuse/api/opentelemetry/types/otel_attribute.py create mode 100644 langfuse/api/opentelemetry/types/otel_attribute_value.py create mode 100644 langfuse/api/opentelemetry/types/otel_resource.py create mode 100644 langfuse/api/opentelemetry/types/otel_resource_span.py create mode 100644 langfuse/api/opentelemetry/types/otel_scope.py create mode 100644 langfuse/api/opentelemetry/types/otel_scope_span.py create mode 100644 langfuse/api/opentelemetry/types/otel_span.py create mode 100644 langfuse/api/opentelemetry/types/otel_trace_response.py create mode 100644 langfuse/api/organizations/__init__.py create mode 100644 langfuse/api/organizations/client.py create mode 100644 langfuse/api/organizations/raw_client.py create mode 100644 langfuse/api/organizations/types/__init__.py create mode 100644 langfuse/api/organizations/types/delete_membership_request.py create mode 100644 langfuse/api/organizations/types/membership_deletion_response.py create mode 100644 langfuse/api/organizations/types/membership_request.py create mode 100644 langfuse/api/organizations/types/membership_response.py create mode 100644 langfuse/api/organizations/types/membership_role.py create mode 100644 langfuse/api/organizations/types/memberships_response.py create mode 100644 langfuse/api/organizations/types/organization_api_key.py create mode 100644 langfuse/api/organizations/types/organization_api_keys_response.py create mode 100644 langfuse/api/organizations/types/organization_project.py create mode 100644 langfuse/api/organizations/types/organization_projects_response.py create mode 100644 langfuse/api/projects/__init__.py create mode 100644 langfuse/api/projects/client.py create mode 100644 langfuse/api/projects/raw_client.py create mode 100644 langfuse/api/projects/types/__init__.py create mode 100644 langfuse/api/projects/types/api_key_deletion_response.py create mode 100644 langfuse/api/projects/types/api_key_list.py create mode 100644 langfuse/api/projects/types/api_key_response.py create mode 100644 langfuse/api/projects/types/api_key_summary.py create mode 100644 langfuse/api/projects/types/project.py create mode 100644 langfuse/api/projects/types/project_deletion_response.py create mode 100644 langfuse/api/projects/types/projects.py rename langfuse/api/{resources => }/prompt_version/__init__.py (76%) create mode 100644 langfuse/api/prompt_version/client.py create mode 100644 langfuse/api/prompt_version/raw_client.py create mode 100644 langfuse/api/prompts/__init__.py create mode 100644 langfuse/api/prompts/client.py create mode 100644 langfuse/api/prompts/raw_client.py create mode 100644 langfuse/api/prompts/types/__init__.py create mode 100644 langfuse/api/prompts/types/base_prompt.py create mode 100644 langfuse/api/prompts/types/chat_message.py create mode 100644 langfuse/api/prompts/types/chat_message_with_placeholders.py create mode 100644 langfuse/api/prompts/types/chat_prompt.py create mode 100644 langfuse/api/prompts/types/create_chat_prompt_request.py create mode 100644 langfuse/api/prompts/types/create_prompt_request.py create mode 100644 langfuse/api/prompts/types/create_text_prompt_request.py create mode 100644 langfuse/api/prompts/types/placeholder_message.py create mode 100644 langfuse/api/prompts/types/prompt.py create mode 100644 langfuse/api/prompts/types/prompt_meta.py create mode 100644 langfuse/api/prompts/types/prompt_meta_list_response.py create mode 100644 langfuse/api/prompts/types/prompt_type.py create mode 100644 langfuse/api/prompts/types/text_prompt.py delete mode 100644 langfuse/api/reference.md delete mode 100644 langfuse/api/resources/__init__.py delete mode 100644 langfuse/api/resources/annotation_queues/__init__.py delete mode 100644 langfuse/api/resources/annotation_queues/client.py delete mode 100644 langfuse/api/resources/annotation_queues/types/__init__.py delete mode 100644 langfuse/api/resources/annotation_queues/types/annotation_queue.py delete mode 100644 langfuse/api/resources/annotation_queues/types/annotation_queue_assignment_request.py delete mode 100644 langfuse/api/resources/annotation_queues/types/annotation_queue_item.py delete mode 100644 langfuse/api/resources/annotation_queues/types/annotation_queue_object_type.py delete mode 100644 langfuse/api/resources/annotation_queues/types/annotation_queue_status.py delete mode 100644 langfuse/api/resources/annotation_queues/types/create_annotation_queue_assignment_response.py delete mode 100644 langfuse/api/resources/annotation_queues/types/create_annotation_queue_item_request.py delete mode 100644 langfuse/api/resources/annotation_queues/types/create_annotation_queue_request.py delete mode 100644 langfuse/api/resources/annotation_queues/types/delete_annotation_queue_assignment_response.py delete mode 100644 langfuse/api/resources/annotation_queues/types/delete_annotation_queue_item_response.py delete mode 100644 langfuse/api/resources/annotation_queues/types/paginated_annotation_queue_items.py delete mode 100644 langfuse/api/resources/annotation_queues/types/paginated_annotation_queues.py delete mode 100644 langfuse/api/resources/annotation_queues/types/update_annotation_queue_item_request.py delete mode 100644 langfuse/api/resources/blob_storage_integrations/__init__.py delete mode 100644 langfuse/api/resources/blob_storage_integrations/client.py delete mode 100644 langfuse/api/resources/blob_storage_integrations/types/__init__.py delete mode 100644 langfuse/api/resources/blob_storage_integrations/types/blob_storage_export_frequency.py delete mode 100644 langfuse/api/resources/blob_storage_integrations/types/blob_storage_export_mode.py delete mode 100644 langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_deletion_response.py delete mode 100644 langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_file_type.py delete mode 100644 langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_response.py delete mode 100644 langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_type.py delete mode 100644 langfuse/api/resources/blob_storage_integrations/types/blob_storage_integrations_response.py delete mode 100644 langfuse/api/resources/blob_storage_integrations/types/create_blob_storage_integration_request.py delete mode 100644 langfuse/api/resources/comments/__init__.py delete mode 100644 langfuse/api/resources/comments/client.py delete mode 100644 langfuse/api/resources/comments/types/__init__.py delete mode 100644 langfuse/api/resources/comments/types/create_comment_request.py delete mode 100644 langfuse/api/resources/comments/types/create_comment_response.py delete mode 100644 langfuse/api/resources/comments/types/get_comments_response.py delete mode 100644 langfuse/api/resources/commons/__init__.py delete mode 100644 langfuse/api/resources/commons/errors/__init__.py delete mode 100644 langfuse/api/resources/commons/errors/access_denied_error.py delete mode 100644 langfuse/api/resources/commons/errors/error.py delete mode 100644 langfuse/api/resources/commons/errors/method_not_allowed_error.py delete mode 100644 langfuse/api/resources/commons/errors/not_found_error.py delete mode 100644 langfuse/api/resources/commons/errors/unauthorized_error.py delete mode 100644 langfuse/api/resources/commons/types/__init__.py delete mode 100644 langfuse/api/resources/commons/types/base_score.py delete mode 100644 langfuse/api/resources/commons/types/base_score_v_1.py delete mode 100644 langfuse/api/resources/commons/types/boolean_score.py delete mode 100644 langfuse/api/resources/commons/types/boolean_score_v_1.py delete mode 100644 langfuse/api/resources/commons/types/categorical_score.py delete mode 100644 langfuse/api/resources/commons/types/categorical_score_v_1.py delete mode 100644 langfuse/api/resources/commons/types/comment.py delete mode 100644 langfuse/api/resources/commons/types/comment_object_type.py delete mode 100644 langfuse/api/resources/commons/types/config_category.py delete mode 100644 langfuse/api/resources/commons/types/dataset.py delete mode 100644 langfuse/api/resources/commons/types/dataset_item.py delete mode 100644 langfuse/api/resources/commons/types/dataset_run.py delete mode 100644 langfuse/api/resources/commons/types/dataset_run_item.py delete mode 100644 langfuse/api/resources/commons/types/dataset_run_with_items.py delete mode 100644 langfuse/api/resources/commons/types/dataset_status.py delete mode 100644 langfuse/api/resources/commons/types/model_price.py delete mode 100644 langfuse/api/resources/commons/types/model_usage_unit.py delete mode 100644 langfuse/api/resources/commons/types/numeric_score.py delete mode 100644 langfuse/api/resources/commons/types/numeric_score_v_1.py delete mode 100644 langfuse/api/resources/commons/types/observation.py delete mode 100644 langfuse/api/resources/commons/types/observation_level.py delete mode 100644 langfuse/api/resources/commons/types/observations_view.py delete mode 100644 langfuse/api/resources/commons/types/pricing_tier_operator.py delete mode 100644 langfuse/api/resources/commons/types/score.py delete mode 100644 langfuse/api/resources/commons/types/score_config.py delete mode 100644 langfuse/api/resources/commons/types/score_data_type.py delete mode 100644 langfuse/api/resources/commons/types/score_source.py delete mode 100644 langfuse/api/resources/commons/types/score_v_1.py delete mode 100644 langfuse/api/resources/commons/types/session.py delete mode 100644 langfuse/api/resources/commons/types/session_with_traces.py delete mode 100644 langfuse/api/resources/commons/types/trace.py delete mode 100644 langfuse/api/resources/commons/types/trace_with_details.py delete mode 100644 langfuse/api/resources/commons/types/trace_with_full_details.py delete mode 100644 langfuse/api/resources/commons/types/usage.py delete mode 100644 langfuse/api/resources/dataset_items/__init__.py delete mode 100644 langfuse/api/resources/dataset_items/client.py delete mode 100644 langfuse/api/resources/dataset_items/types/__init__.py delete mode 100644 langfuse/api/resources/dataset_items/types/create_dataset_item_request.py delete mode 100644 langfuse/api/resources/dataset_items/types/delete_dataset_item_response.py delete mode 100644 langfuse/api/resources/dataset_items/types/paginated_dataset_items.py delete mode 100644 langfuse/api/resources/dataset_run_items/__init__.py delete mode 100644 langfuse/api/resources/dataset_run_items/client.py delete mode 100644 langfuse/api/resources/dataset_run_items/types/__init__.py delete mode 100644 langfuse/api/resources/dataset_run_items/types/create_dataset_run_item_request.py delete mode 100644 langfuse/api/resources/dataset_run_items/types/paginated_dataset_run_items.py delete mode 100644 langfuse/api/resources/datasets/__init__.py delete mode 100644 langfuse/api/resources/datasets/client.py delete mode 100644 langfuse/api/resources/datasets/types/__init__.py delete mode 100644 langfuse/api/resources/datasets/types/create_dataset_request.py delete mode 100644 langfuse/api/resources/datasets/types/delete_dataset_run_response.py delete mode 100644 langfuse/api/resources/datasets/types/paginated_dataset_runs.py delete mode 100644 langfuse/api/resources/datasets/types/paginated_datasets.py delete mode 100644 langfuse/api/resources/health/__init__.py delete mode 100644 langfuse/api/resources/health/client.py delete mode 100644 langfuse/api/resources/health/errors/__init__.py delete mode 100644 langfuse/api/resources/health/errors/service_unavailable_error.py delete mode 100644 langfuse/api/resources/health/types/__init__.py delete mode 100644 langfuse/api/resources/health/types/health_response.py delete mode 100644 langfuse/api/resources/ingestion/__init__.py delete mode 100644 langfuse/api/resources/ingestion/types/__init__.py delete mode 100644 langfuse/api/resources/ingestion/types/base_event.py delete mode 100644 langfuse/api/resources/ingestion/types/create_event_body.py delete mode 100644 langfuse/api/resources/ingestion/types/create_event_event.py delete mode 100644 langfuse/api/resources/ingestion/types/create_generation_body.py delete mode 100644 langfuse/api/resources/ingestion/types/create_generation_event.py delete mode 100644 langfuse/api/resources/ingestion/types/create_observation_event.py delete mode 100644 langfuse/api/resources/ingestion/types/create_span_body.py delete mode 100644 langfuse/api/resources/ingestion/types/create_span_event.py delete mode 100644 langfuse/api/resources/ingestion/types/ingestion_error.py delete mode 100644 langfuse/api/resources/ingestion/types/ingestion_event.py delete mode 100644 langfuse/api/resources/ingestion/types/ingestion_response.py delete mode 100644 langfuse/api/resources/ingestion/types/ingestion_success.py delete mode 100644 langfuse/api/resources/ingestion/types/observation_body.py delete mode 100644 langfuse/api/resources/ingestion/types/observation_type.py delete mode 100644 langfuse/api/resources/ingestion/types/open_ai_completion_usage_schema.py delete mode 100644 langfuse/api/resources/ingestion/types/open_ai_response_usage_schema.py delete mode 100644 langfuse/api/resources/ingestion/types/open_ai_usage.py delete mode 100644 langfuse/api/resources/ingestion/types/optional_observation_body.py delete mode 100644 langfuse/api/resources/ingestion/types/score_body.py delete mode 100644 langfuse/api/resources/ingestion/types/score_event.py delete mode 100644 langfuse/api/resources/ingestion/types/sdk_log_body.py delete mode 100644 langfuse/api/resources/ingestion/types/sdk_log_event.py delete mode 100644 langfuse/api/resources/ingestion/types/trace_body.py delete mode 100644 langfuse/api/resources/ingestion/types/trace_event.py delete mode 100644 langfuse/api/resources/ingestion/types/update_event_body.py delete mode 100644 langfuse/api/resources/ingestion/types/update_generation_body.py delete mode 100644 langfuse/api/resources/ingestion/types/update_generation_event.py delete mode 100644 langfuse/api/resources/ingestion/types/update_observation_event.py delete mode 100644 langfuse/api/resources/ingestion/types/update_span_body.py delete mode 100644 langfuse/api/resources/ingestion/types/update_span_event.py delete mode 100644 langfuse/api/resources/llm_connections/__init__.py delete mode 100644 langfuse/api/resources/llm_connections/client.py delete mode 100644 langfuse/api/resources/llm_connections/types/__init__.py delete mode 100644 langfuse/api/resources/llm_connections/types/llm_adapter.py delete mode 100644 langfuse/api/resources/llm_connections/types/llm_connection.py delete mode 100644 langfuse/api/resources/llm_connections/types/paginated_llm_connections.py delete mode 100644 langfuse/api/resources/llm_connections/types/upsert_llm_connection_request.py delete mode 100644 langfuse/api/resources/media/__init__.py delete mode 100644 langfuse/api/resources/media/client.py delete mode 100644 langfuse/api/resources/media/types/__init__.py delete mode 100644 langfuse/api/resources/media/types/get_media_response.py delete mode 100644 langfuse/api/resources/media/types/get_media_upload_url_request.py delete mode 100644 langfuse/api/resources/media/types/get_media_upload_url_response.py delete mode 100644 langfuse/api/resources/media/types/media_content_type.py delete mode 100644 langfuse/api/resources/media/types/patch_media_body.py delete mode 100644 langfuse/api/resources/metrics/__init__.py delete mode 100644 langfuse/api/resources/metrics/types/__init__.py delete mode 100644 langfuse/api/resources/metrics/types/metrics_response.py delete mode 100644 langfuse/api/resources/models/__init__.py delete mode 100644 langfuse/api/resources/models/client.py delete mode 100644 langfuse/api/resources/models/types/__init__.py delete mode 100644 langfuse/api/resources/models/types/paginated_models.py delete mode 100644 langfuse/api/resources/observations/__init__.py delete mode 100644 langfuse/api/resources/observations/types/__init__.py delete mode 100644 langfuse/api/resources/observations/types/observations.py delete mode 100644 langfuse/api/resources/observations/types/observations_views.py delete mode 100644 langfuse/api/resources/opentelemetry/__init__.py delete mode 100644 langfuse/api/resources/opentelemetry/types/__init__.py delete mode 100644 langfuse/api/resources/opentelemetry/types/otel_attribute.py delete mode 100644 langfuse/api/resources/opentelemetry/types/otel_attribute_value.py delete mode 100644 langfuse/api/resources/opentelemetry/types/otel_resource.py delete mode 100644 langfuse/api/resources/opentelemetry/types/otel_resource_span.py delete mode 100644 langfuse/api/resources/opentelemetry/types/otel_scope.py delete mode 100644 langfuse/api/resources/opentelemetry/types/otel_scope_span.py delete mode 100644 langfuse/api/resources/opentelemetry/types/otel_span.py delete mode 100644 langfuse/api/resources/opentelemetry/types/otel_trace_response.py delete mode 100644 langfuse/api/resources/organizations/__init__.py delete mode 100644 langfuse/api/resources/organizations/client.py delete mode 100644 langfuse/api/resources/organizations/types/__init__.py delete mode 100644 langfuse/api/resources/organizations/types/delete_membership_request.py delete mode 100644 langfuse/api/resources/organizations/types/membership_deletion_response.py delete mode 100644 langfuse/api/resources/organizations/types/membership_request.py delete mode 100644 langfuse/api/resources/organizations/types/membership_response.py delete mode 100644 langfuse/api/resources/organizations/types/membership_role.py delete mode 100644 langfuse/api/resources/organizations/types/memberships_response.py delete mode 100644 langfuse/api/resources/organizations/types/organization_api_key.py delete mode 100644 langfuse/api/resources/organizations/types/organization_api_keys_response.py delete mode 100644 langfuse/api/resources/organizations/types/organization_project.py delete mode 100644 langfuse/api/resources/organizations/types/organization_projects_response.py delete mode 100644 langfuse/api/resources/projects/__init__.py delete mode 100644 langfuse/api/resources/projects/client.py delete mode 100644 langfuse/api/resources/projects/types/__init__.py delete mode 100644 langfuse/api/resources/projects/types/api_key_deletion_response.py delete mode 100644 langfuse/api/resources/projects/types/api_key_list.py delete mode 100644 langfuse/api/resources/projects/types/api_key_response.py delete mode 100644 langfuse/api/resources/projects/types/api_key_summary.py delete mode 100644 langfuse/api/resources/projects/types/project.py delete mode 100644 langfuse/api/resources/projects/types/project_deletion_response.py delete mode 100644 langfuse/api/resources/projects/types/projects.py delete mode 100644 langfuse/api/resources/prompt_version/client.py delete mode 100644 langfuse/api/resources/prompts/__init__.py delete mode 100644 langfuse/api/resources/prompts/client.py delete mode 100644 langfuse/api/resources/prompts/types/__init__.py delete mode 100644 langfuse/api/resources/prompts/types/base_prompt.py delete mode 100644 langfuse/api/resources/prompts/types/chat_message.py delete mode 100644 langfuse/api/resources/prompts/types/chat_message_with_placeholders.py delete mode 100644 langfuse/api/resources/prompts/types/chat_prompt.py delete mode 100644 langfuse/api/resources/prompts/types/create_chat_prompt_request.py delete mode 100644 langfuse/api/resources/prompts/types/create_prompt_request.py delete mode 100644 langfuse/api/resources/prompts/types/create_text_prompt_request.py delete mode 100644 langfuse/api/resources/prompts/types/placeholder_message.py delete mode 100644 langfuse/api/resources/prompts/types/prompt.py delete mode 100644 langfuse/api/resources/prompts/types/prompt_meta.py delete mode 100644 langfuse/api/resources/prompts/types/prompt_meta_list_response.py delete mode 100644 langfuse/api/resources/prompts/types/prompt_type.py delete mode 100644 langfuse/api/resources/prompts/types/text_prompt.py delete mode 100644 langfuse/api/resources/scim/__init__.py delete mode 100644 langfuse/api/resources/scim/client.py delete mode 100644 langfuse/api/resources/scim/types/__init__.py delete mode 100644 langfuse/api/resources/scim/types/authentication_scheme.py delete mode 100644 langfuse/api/resources/scim/types/bulk_config.py delete mode 100644 langfuse/api/resources/scim/types/empty_response.py delete mode 100644 langfuse/api/resources/scim/types/filter_config.py delete mode 100644 langfuse/api/resources/scim/types/resource_meta.py delete mode 100644 langfuse/api/resources/scim/types/resource_type.py delete mode 100644 langfuse/api/resources/scim/types/resource_types_response.py delete mode 100644 langfuse/api/resources/scim/types/schema_extension.py delete mode 100644 langfuse/api/resources/scim/types/schema_resource.py delete mode 100644 langfuse/api/resources/scim/types/schemas_response.py delete mode 100644 langfuse/api/resources/scim/types/scim_email.py delete mode 100644 langfuse/api/resources/scim/types/scim_feature_support.py delete mode 100644 langfuse/api/resources/scim/types/scim_name.py delete mode 100644 langfuse/api/resources/scim/types/scim_user.py delete mode 100644 langfuse/api/resources/scim/types/scim_users_list_response.py delete mode 100644 langfuse/api/resources/scim/types/service_provider_config.py delete mode 100644 langfuse/api/resources/scim/types/user_meta.py delete mode 100644 langfuse/api/resources/score/__init__.py delete mode 100644 langfuse/api/resources/score/client.py delete mode 100644 langfuse/api/resources/score/types/__init__.py delete mode 100644 langfuse/api/resources/score/types/create_score_request.py delete mode 100644 langfuse/api/resources/score/types/create_score_response.py delete mode 100644 langfuse/api/resources/score_configs/__init__.py delete mode 100644 langfuse/api/resources/score_configs/client.py delete mode 100644 langfuse/api/resources/score_configs/types/__init__.py delete mode 100644 langfuse/api/resources/score_configs/types/create_score_config_request.py delete mode 100644 langfuse/api/resources/score_configs/types/score_configs.py delete mode 100644 langfuse/api/resources/score_configs/types/update_score_config_request.py delete mode 100644 langfuse/api/resources/score_v_2/__init__.py delete mode 100644 langfuse/api/resources/score_v_2/types/__init__.py delete mode 100644 langfuse/api/resources/score_v_2/types/get_scores_response.py delete mode 100644 langfuse/api/resources/score_v_2/types/get_scores_response_data.py delete mode 100644 langfuse/api/resources/score_v_2/types/get_scores_response_data_boolean.py delete mode 100644 langfuse/api/resources/score_v_2/types/get_scores_response_data_categorical.py delete mode 100644 langfuse/api/resources/score_v_2/types/get_scores_response_data_numeric.py delete mode 100644 langfuse/api/resources/score_v_2/types/get_scores_response_trace_data.py delete mode 100644 langfuse/api/resources/sessions/__init__.py delete mode 100644 langfuse/api/resources/sessions/client.py delete mode 100644 langfuse/api/resources/sessions/types/__init__.py delete mode 100644 langfuse/api/resources/sessions/types/paginated_sessions.py delete mode 100644 langfuse/api/resources/trace/__init__.py delete mode 100644 langfuse/api/resources/trace/types/__init__.py delete mode 100644 langfuse/api/resources/trace/types/delete_trace_response.py delete mode 100644 langfuse/api/resources/trace/types/sort.py delete mode 100644 langfuse/api/resources/trace/types/traces.py delete mode 100644 langfuse/api/resources/utils/__init__.py delete mode 100644 langfuse/api/resources/utils/resources/__init__.py delete mode 100644 langfuse/api/resources/utils/resources/pagination/types/__init__.py delete mode 100644 langfuse/api/resources/utils/resources/pagination/types/meta_response.py create mode 100644 langfuse/api/scim/__init__.py create mode 100644 langfuse/api/scim/client.py create mode 100644 langfuse/api/scim/raw_client.py create mode 100644 langfuse/api/scim/types/__init__.py create mode 100644 langfuse/api/scim/types/authentication_scheme.py create mode 100644 langfuse/api/scim/types/bulk_config.py create mode 100644 langfuse/api/scim/types/empty_response.py create mode 100644 langfuse/api/scim/types/filter_config.py create mode 100644 langfuse/api/scim/types/resource_meta.py create mode 100644 langfuse/api/scim/types/resource_type.py create mode 100644 langfuse/api/scim/types/resource_types_response.py create mode 100644 langfuse/api/scim/types/schema_extension.py create mode 100644 langfuse/api/scim/types/schema_resource.py create mode 100644 langfuse/api/scim/types/schemas_response.py create mode 100644 langfuse/api/scim/types/scim_email.py create mode 100644 langfuse/api/scim/types/scim_feature_support.py create mode 100644 langfuse/api/scim/types/scim_name.py create mode 100644 langfuse/api/scim/types/scim_user.py create mode 100644 langfuse/api/scim/types/scim_users_list_response.py create mode 100644 langfuse/api/scim/types/service_provider_config.py create mode 100644 langfuse/api/scim/types/user_meta.py create mode 100644 langfuse/api/score/__init__.py create mode 100644 langfuse/api/score/client.py create mode 100644 langfuse/api/score/raw_client.py create mode 100644 langfuse/api/score/types/__init__.py create mode 100644 langfuse/api/score/types/create_score_request.py create mode 100644 langfuse/api/score/types/create_score_response.py create mode 100644 langfuse/api/score_configs/__init__.py create mode 100644 langfuse/api/score_configs/client.py create mode 100644 langfuse/api/score_configs/raw_client.py create mode 100644 langfuse/api/score_configs/types/__init__.py create mode 100644 langfuse/api/score_configs/types/create_score_config_request.py create mode 100644 langfuse/api/score_configs/types/score_configs.py create mode 100644 langfuse/api/score_configs/types/update_score_config_request.py create mode 100644 langfuse/api/score_v2/__init__.py create mode 100644 langfuse/api/score_v2/client.py rename langfuse/api/{resources/score_v_2/client.py => score_v2/raw_client.py} (56%) create mode 100644 langfuse/api/score_v2/types/__init__.py create mode 100644 langfuse/api/score_v2/types/get_scores_response.py create mode 100644 langfuse/api/score_v2/types/get_scores_response_data.py create mode 100644 langfuse/api/score_v2/types/get_scores_response_data_boolean.py create mode 100644 langfuse/api/score_v2/types/get_scores_response_data_categorical.py create mode 100644 langfuse/api/score_v2/types/get_scores_response_data_numeric.py create mode 100644 langfuse/api/score_v2/types/get_scores_response_trace_data.py create mode 100644 langfuse/api/sessions/__init__.py create mode 100644 langfuse/api/sessions/client.py create mode 100644 langfuse/api/sessions/raw_client.py create mode 100644 langfuse/api/sessions/types/__init__.py create mode 100644 langfuse/api/sessions/types/paginated_sessions.py create mode 100644 langfuse/api/trace/__init__.py rename langfuse/api/{resources => }/trace/client.py (61%) create mode 100644 langfuse/api/trace/raw_client.py create mode 100644 langfuse/api/trace/types/__init__.py create mode 100644 langfuse/api/trace/types/delete_trace_response.py create mode 100644 langfuse/api/trace/types/sort.py create mode 100644 langfuse/api/trace/types/traces.py create mode 100644 langfuse/api/utils/__init__.py create mode 100644 langfuse/api/utils/pagination/__init__.py create mode 100644 langfuse/api/utils/pagination/types/__init__.py create mode 100644 langfuse/api/utils/pagination/types/meta_response.py diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py index a3f653ada..6ba0e61c1 100644 --- a/langfuse/_client/client.py +++ b/langfuse/_client/client.py @@ -78,15 +78,15 @@ from langfuse._utils import _get_timestamp from langfuse._utils.parse_error import handle_fern_exception from langfuse._utils.prompt_cache import PromptCache -from langfuse.api.resources.commons.errors.error import Error -from langfuse.api.resources.commons.errors.not_found_error import NotFoundError -from langfuse.api.resources.ingestion.types.score_body import ScoreBody -from langfuse.api.resources.prompts.types import ( +from langfuse.api.datasets import Dataset, DatasetItem, DatasetStatus +from langfuse.api.ingestion import ScoreBody +from langfuse.api.prompts import ( CreatePromptRequest_Chat, CreatePromptRequest_Text, Prompt_Chat, Prompt_Text, ) +from langfuse.api.utils import Error, NotFoundError from langfuse.batch_evaluation import ( BatchEvaluationResult, BatchEvaluationResumeToken, @@ -112,12 +112,7 @@ ChatMessageDict, ChatMessageWithPlaceholdersDict, ChatPromptClient, - CreateDatasetItemRequest, - CreateDatasetRequest, CreateDatasetRunItemRequest, - Dataset, - DatasetItem, - DatasetStatus, MapValue, PromptClient, TextPromptClient, @@ -3271,16 +3266,15 @@ def create_dataset( Dataset: The created dataset as returned by the Langfuse API. """ try: - body = CreateDatasetRequest( + langfuse_logger.debug(f"Creating datasets {name}") + + return self.api.datasets.create( name=name, description=description, metadata=metadata, - inputSchema=input_schema, - expectedOutputSchema=expected_output_schema, + input_schema=input_schema, + expected_output_schema=expected_output_schema, ) - langfuse_logger.debug(f"Creating datasets {body}") - - return self.api.datasets.create(request=body) except Error as e: handle_fern_exception(e) @@ -3331,18 +3325,18 @@ def create_dataset_item( ``` """ try: - body = CreateDatasetItemRequest( - datasetName=dataset_name, + langfuse_logger.debug(f"Creating dataset item for dataset {dataset_name}") + + return self.api.dataset_items.create( + dataset_name=dataset_name, input=input, - expectedOutput=expected_output, + expected_output=expected_output, metadata=metadata, - sourceTraceId=source_trace_id, - sourceObservationId=source_observation_id, + source_trace_id=source_trace_id, + source_observation_id=source_observation_id, status=status, id=id, ) - langfuse_logger.debug(f"Creating dataset item {body}") - return self.api.dataset_items.create(request=body) except Error as e: handle_fern_exception(e) raise e @@ -3711,7 +3705,7 @@ def create_prompt( labels=labels, tags=tags, config=config or {}, - commitMessage=commit_message, + commit_message=commit_message, type="chat", ) ) @@ -3731,7 +3725,7 @@ def create_prompt( labels=labels, tags=tags, config=config or {}, - commitMessage=commit_message, + commit_message=commit_message, type="text", ) diff --git a/langfuse/_client/datasets.py b/langfuse/_client/datasets.py index 0a9a0312c..8f1163b72 100644 --- a/langfuse/_client/datasets.py +++ b/langfuse/_client/datasets.py @@ -4,6 +4,12 @@ from opentelemetry.util._decorator import _agnosticcontextmanager +from langfuse.api.datasets import ( + CreateDatasetRunItemRequest, + Dataset, + DatasetItem, + DatasetStatus, +) from langfuse.batch_evaluation import CompositeEvaluatorFunction from langfuse.experiment import ( EvaluatorFunction, @@ -11,12 +17,6 @@ RunEvaluatorFunction, TaskFunction, ) -from langfuse.model import ( - CreateDatasetRunItemRequest, - Dataset, - DatasetItem, - DatasetStatus, -) from .span import LangfuseSpan diff --git a/langfuse/_client/resource_manager.py b/langfuse/_client/resource_manager.py index 08c008234..1820807c6 100644 --- a/langfuse/_client/resource_manager.py +++ b/langfuse/_client/resource_manager.py @@ -42,7 +42,7 @@ from langfuse._utils.environment import get_common_release_envs from langfuse._utils.prompt_cache import PromptCache from langfuse._utils.request import LangfuseClient -from langfuse.api.client import AsyncFernLangfuse, FernLangfuse +from langfuse.api.client import AsyncLangfuseAPI, LangfuseAPI from langfuse.logger import langfuse_logger from langfuse.types import MaskFunction @@ -213,7 +213,7 @@ def _initialize_instance( client_headers = additional_headers if additional_headers else {} self.httpx_client = httpx.Client(timeout=timeout, headers=client_headers) - self.api = FernLangfuse( + self.api = LangfuseAPI( base_url=base_url, username=self.public_key, password=secret_key, @@ -223,7 +223,7 @@ def _initialize_instance( httpx_client=self.httpx_client, timeout=timeout, ) - self.async_api = AsyncFernLangfuse( + self.async_api = AsyncLangfuseAPI( base_url=base_url, username=self.public_key, password=secret_key, diff --git a/langfuse/_task_manager/media_manager.py b/langfuse/_task_manager/media_manager.py index 1a32e3d60..388a5c2a1 100644 --- a/langfuse/_task_manager/media_manager.py +++ b/langfuse/_task_manager/media_manager.py @@ -10,10 +10,9 @@ from langfuse._client.environment_variables import LANGFUSE_MEDIA_UPLOAD_ENABLED from langfuse._utils import _get_timestamp -from langfuse.api import GetMediaUploadUrlRequest, PatchMediaBody -from langfuse.api.client import FernLangfuse +from langfuse.api.client import LangfuseAPI from langfuse.api.core import ApiError -from langfuse.api.resources.media.types.media_content_type import MediaContentType +from langfuse.api.media import MediaContentType from langfuse.media import LangfuseMedia from .media_upload_queue import UploadMediaJob @@ -28,7 +27,7 @@ class MediaManager: def __init__( self, *, - api_client: FernLangfuse, + api_client: LangfuseAPI, media_upload_queue: Queue, max_retries: Optional[int] = 3, ): @@ -219,14 +218,12 @@ def _process_upload_media_job( ) -> None: upload_url_response = self._request_with_backoff( self._api_client.media.get_upload_url, - request=GetMediaUploadUrlRequest( - contentLength=data["content_length"], - contentType=cast(MediaContentType, data["content_type"]), - sha256Hash=data["content_sha256_hash"], - field=data["field"], - traceId=data["trace_id"], - observationId=data["observation_id"], - ), + content_length=data["content_length"], + content_type=cast(MediaContentType, data["content_type"]), + sha256hash=data["content_sha256_hash"], + field=data["field"], + trace_id=data["trace_id"], + observation_id=data["observation_id"], ) upload_url = upload_url_response.upload_url @@ -266,12 +263,10 @@ def _process_upload_media_job( self._request_with_backoff( self._api_client.media.patch, media_id=data["media_id"], - request=PatchMediaBody( - uploadedAt=_get_timestamp(), - uploadHttpStatus=upload_response.status_code, - uploadHttpError=upload_response.text, - uploadTimeMs=upload_time_ms, - ), + uploaded_at=_get_timestamp(), + upload_http_status=upload_response.status_code, + upload_http_error=upload_response.text, + upload_time_ms=upload_time_ms, ) self._log.debug( diff --git a/langfuse/_utils/parse_error.py b/langfuse/_utils/parse_error.py index cb5749f93..86aa6129d 100644 --- a/langfuse/_utils/parse_error.py +++ b/langfuse/_utils/parse_error.py @@ -4,16 +4,16 @@ # our own api errors from langfuse._utils.request import APIError, APIErrors from langfuse.api.core import ApiError +from langfuse.api.health import ServiceUnavailableError # fern api errors -from langfuse.api.resources.commons.errors import ( +from langfuse.api.utils import ( AccessDeniedError, Error, MethodNotAllowedError, NotFoundError, UnauthorizedError, ) -from langfuse.api.resources.health.errors import ServiceUnavailableError SUPPORT_URL = "https://langfuse.com/support" API_DOCS_URL = "https://api.reference.langfuse.com" diff --git a/langfuse/api/.fern/metadata.json b/langfuse/api/.fern/metadata.json new file mode 100644 index 000000000..3e02d7184 --- /dev/null +++ b/langfuse/api/.fern/metadata.json @@ -0,0 +1,10 @@ +{ + "cliVersion": "3.24.3", + "generatorName": "fernapi/fern-python-sdk", + "generatorVersion": "4.46.2", + "generatorConfig": { + "client": { + "class_name": "LangfuseAPI" + } + } +} \ No newline at end of file diff --git a/langfuse/api/README.md b/langfuse/api/README.md deleted file mode 100644 index 47de89ea3..000000000 --- a/langfuse/api/README.md +++ /dev/null @@ -1,161 +0,0 @@ -# Langfuse Python Library - -[![fern shield](https://img.shields.io/badge/%F0%9F%8C%BF-Built%20with%20Fern-brightgreen)](https://buildwithfern.com?utm_source=github&utm_medium=github&utm_campaign=readme&utm_source=Langfuse%2FPython) -[![pypi](https://img.shields.io/pypi/v/langfuse)](https://pypi.python.org/pypi/langfuse) - -The Langfuse Python library provides convenient access to the Langfuse APIs from Python. - -## Table of Contents - -- [Installation](#installation) -- [Usage](#usage) -- [Async Client](#async-client) -- [Exception Handling](#exception-handling) -- [Advanced](#advanced) - - [Retries](#retries) - - [Timeouts](#timeouts) - - [Custom Client](#custom-client) -- [Contributing](#contributing) - -## Installation - -```sh -pip install langfuse -``` - -## Usage - -Instantiate and use the client with the following: - -```python -from langfuse import CreateAnnotationQueueRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.annotation_queues.create_queue( - request=CreateAnnotationQueueRequest( - name="name", - score_config_ids=["scoreConfigIds", "scoreConfigIds"], - ), -) -``` - -## Async Client - -The SDK also exports an `async` client so that you can make non-blocking calls to our API. - -```python -import asyncio - -from langfuse import CreateAnnotationQueueRequest -from langfuse.client import AsyncFernLangfuse - -client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) - - -async def main() -> None: - await client.annotation_queues.create_queue( - request=CreateAnnotationQueueRequest( - name="name", - score_config_ids=["scoreConfigIds", "scoreConfigIds"], - ), - ) - - -asyncio.run(main()) -``` - -## Exception Handling - -When the API returns a non-success status code (4xx or 5xx response), a subclass of the following error -will be thrown. - -```python -from .api_error import ApiError - -try: - client.annotation_queues.create_queue(...) -except ApiError as e: - print(e.status_code) - print(e.body) -``` - -## Advanced - -### Retries - -The SDK is instrumented with automatic retries with exponential backoff. A request will be retried as long -as the request is deemed retriable and the number of retry attempts has not grown larger than the configured -retry limit (default: 2). - -A request is deemed retriable when any of the following HTTP status codes is returned: - -- [408](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) (Timeout) -- [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) (Too Many Requests) -- [5XX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500) (Internal Server Errors) - -Use the `max_retries` request option to configure this behavior. - -```python -client.annotation_queues.create_queue(...,{ - max_retries=1 -}) -``` - -### Timeouts - -The SDK defaults to a 60 second timeout. You can configure this with a timeout option at the client or request level. - -```python - -from langfuse.client import FernLangfuse - -client = FernLangfuse(..., { timeout=20.0 }, ) - - -# Override timeout for a specific method -client.annotation_queues.create_queue(...,{ - timeout_in_seconds=1 -}) -``` - -### Custom Client - -You can override the `httpx` client to customize it for your use-case. Some common use-cases include support for proxies -and transports. -```python -import httpx -from langfuse.client import FernLangfuse - -client = FernLangfuse( - ..., - http_client=httpx.Client( - proxies="http://my.test.proxy.example.com", - transport=httpx.HTTPTransport(local_address="0.0.0.0"), - ), -) -``` - -## Contributing - -While we value open-source contributions to this SDK, this library is generated programmatically. -Additions made directly to this library would have to be moved over to our generation code, -otherwise they would be overwritten upon the next generated release. Feel free to open a PR as -a proof of concept, but know that we will not be able to merge it as-is. We suggest opening -an issue first to discuss with us! - -On the other hand, contributions to the README are always very welcome! diff --git a/langfuse/api/__init__.py b/langfuse/api/__init__.py index c958219d5..ed4ae1708 100644 --- a/langfuse/api/__init__.py +++ b/langfuse/api/__init__.py @@ -1,254 +1,565 @@ # This file was auto-generated by Fern from our API Definition. -from .resources import ( - AccessDeniedError, - AnnotationQueue, - AnnotationQueueAssignmentRequest, - AnnotationQueueItem, - AnnotationQueueObjectType, - AnnotationQueueStatus, - ApiKeyDeletionResponse, - ApiKeyList, - ApiKeyResponse, - ApiKeySummary, - AuthenticationScheme, - BaseEvent, - BasePrompt, - BaseScore, - BaseScoreV1, - BlobStorageExportFrequency, - BlobStorageExportMode, - BlobStorageIntegrationDeletionResponse, - BlobStorageIntegrationFileType, - BlobStorageIntegrationResponse, - BlobStorageIntegrationType, - BlobStorageIntegrationsResponse, - BooleanScore, - BooleanScoreV1, - BulkConfig, - CategoricalScore, - CategoricalScoreV1, - ChatMessage, - ChatMessageWithPlaceholders, - ChatMessageWithPlaceholders_Chatmessage, - ChatMessageWithPlaceholders_Placeholder, - ChatPrompt, - Comment, - CommentObjectType, - ConfigCategory, - CreateAnnotationQueueAssignmentResponse, - CreateAnnotationQueueItemRequest, - CreateAnnotationQueueRequest, - CreateBlobStorageIntegrationRequest, - CreateChatPromptRequest, - CreateCommentRequest, - CreateCommentResponse, - CreateDatasetItemRequest, - CreateDatasetRequest, - CreateDatasetRunItemRequest, - CreateEventBody, - CreateEventEvent, - CreateGenerationBody, - CreateGenerationEvent, - CreateModelRequest, - CreateObservationEvent, - CreatePromptRequest, - CreatePromptRequest_Chat, - CreatePromptRequest_Text, - CreateScoreConfigRequest, - CreateScoreRequest, - CreateScoreResponse, - CreateScoreValue, - CreateSpanBody, - CreateSpanEvent, - CreateTextPromptRequest, - Dataset, - DatasetItem, - DatasetRun, - DatasetRunItem, - DatasetRunWithItems, - DatasetStatus, - DeleteAnnotationQueueAssignmentResponse, - DeleteAnnotationQueueItemResponse, - DeleteDatasetItemResponse, - DeleteDatasetRunResponse, - DeleteMembershipRequest, - DeleteTraceResponse, - EmptyResponse, - Error, - FilterConfig, - GetCommentsResponse, - GetMediaResponse, - GetMediaUploadUrlRequest, - GetMediaUploadUrlResponse, - GetScoresResponse, - GetScoresResponseData, - GetScoresResponseDataBoolean, - GetScoresResponseDataCategorical, - GetScoresResponseDataNumeric, - GetScoresResponseData_Boolean, - GetScoresResponseData_Categorical, - GetScoresResponseData_Numeric, - GetScoresResponseTraceData, - HealthResponse, - IngestionError, - IngestionEvent, - IngestionEvent_EventCreate, - IngestionEvent_GenerationCreate, - IngestionEvent_GenerationUpdate, - IngestionEvent_ObservationCreate, - IngestionEvent_ObservationUpdate, - IngestionEvent_ScoreCreate, - IngestionEvent_SdkLog, - IngestionEvent_SpanCreate, - IngestionEvent_SpanUpdate, - IngestionEvent_TraceCreate, - IngestionResponse, - IngestionSuccess, - IngestionUsage, - LlmAdapter, - LlmConnection, - MapValue, - MediaContentType, - MembershipDeletionResponse, - MembershipRequest, - MembershipResponse, - MembershipRole, - MembershipsResponse, - MethodNotAllowedError, - MetricsResponse, - Model, - ModelPrice, - ModelUsageUnit, - NotFoundError, - NumericScore, - NumericScoreV1, - Observation, - ObservationBody, - ObservationLevel, - ObservationType, - Observations, - ObservationsView, - ObservationsViews, - OpenAiCompletionUsageSchema, - OpenAiResponseUsageSchema, - OpenAiUsage, - OptionalObservationBody, - OrganizationApiKey, - OrganizationApiKeysResponse, - OrganizationProject, - OrganizationProjectsResponse, - OtelAttribute, - OtelAttributeValue, - OtelResource, - OtelResourceSpan, - OtelScope, - OtelScopeSpan, - OtelSpan, - OtelTraceResponse, - PaginatedAnnotationQueueItems, - PaginatedAnnotationQueues, - PaginatedDatasetItems, - PaginatedDatasetRunItems, - PaginatedDatasetRuns, - PaginatedDatasets, - PaginatedLlmConnections, - PaginatedModels, - PaginatedSessions, - PatchMediaBody, - PlaceholderMessage, - PricingTier, - PricingTierCondition, - PricingTierInput, - PricingTierOperator, - Project, - ProjectDeletionResponse, - Projects, - Prompt, - PromptMeta, - PromptMetaListResponse, - PromptType, - Prompt_Chat, - Prompt_Text, - ResourceMeta, - ResourceType, - ResourceTypesResponse, - SchemaExtension, - SchemaResource, - SchemasResponse, - ScimEmail, - ScimFeatureSupport, - ScimName, - ScimUser, - ScimUsersListResponse, - Score, - ScoreBody, - ScoreConfig, - ScoreConfigs, - ScoreDataType, - ScoreEvent, - ScoreSource, - ScoreV1, - ScoreV1_Boolean, - ScoreV1_Categorical, - ScoreV1_Numeric, - Score_Boolean, - Score_Categorical, - Score_Numeric, - SdkLogBody, - SdkLogEvent, - ServiceProviderConfig, - ServiceUnavailableError, - Session, - SessionWithTraces, - Sort, - TextPrompt, - Trace, - TraceBody, - TraceEvent, - TraceWithDetails, - TraceWithFullDetails, - Traces, - UnauthorizedError, - UpdateAnnotationQueueItemRequest, - UpdateEventBody, - UpdateGenerationBody, - UpdateGenerationEvent, - UpdateObservationEvent, - UpdateScoreConfigRequest, - UpdateSpanBody, - UpdateSpanEvent, - UpsertLlmConnectionRequest, - Usage, - UsageDetails, - UserMeta, - annotation_queues, - blob_storage_integrations, - comments, - commons, - dataset_items, - dataset_run_items, - datasets, - health, - ingestion, - llm_connections, - media, - metrics, - models, - observations, - opentelemetry, - organizations, - projects, - prompt_version, - prompts, - scim, - score, - score_configs, - score_v_2, - sessions, - trace, - utils, -) +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from . import ( + annotation_queues, + blob_storage_integrations, + comments, + commons, + dataset_items, + dataset_run_items, + datasets, + health, + ingestion, + llm_connections, + media, + metrics, + models, + observations, + opentelemetry, + organizations, + projects, + prompt_version, + prompts, + scim, + score, + score_configs, + score_v2, + sessions, + trace, + utils, + ) + from .annotation_queues import ( + AnnotationQueue, + AnnotationQueueAssignmentRequest, + AnnotationQueueItem, + AnnotationQueueObjectType, + AnnotationQueueStatus, + CreateAnnotationQueueAssignmentResponse, + CreateAnnotationQueueItemRequest, + CreateAnnotationQueueRequest, + DeleteAnnotationQueueAssignmentResponse, + DeleteAnnotationQueueItemResponse, + PaginatedAnnotationQueueItems, + PaginatedAnnotationQueues, + UpdateAnnotationQueueItemRequest, + ) + from .blob_storage_integrations import ( + BlobStorageExportFrequency, + BlobStorageExportMode, + BlobStorageIntegrationDeletionResponse, + BlobStorageIntegrationFileType, + BlobStorageIntegrationResponse, + BlobStorageIntegrationType, + BlobStorageIntegrationsResponse, + CreateBlobStorageIntegrationRequest, + ) + from .client import AsyncLangfuseAPI, LangfuseAPI + from .comments import ( + CreateCommentRequest, + CreateCommentResponse, + GetCommentsResponse, + ) + from .commons import ( + AccessDeniedError, + BaseScore, + BaseScoreV1, + BooleanScore, + BooleanScoreV1, + CategoricalScore, + CategoricalScoreV1, + Comment, + CommentObjectType, + ConfigCategory, + CreateScoreValue, + Dataset, + DatasetItem, + DatasetRun, + DatasetRunItem, + DatasetRunWithItems, + DatasetStatus, + Error, + MapValue, + MethodNotAllowedError, + Model, + ModelPrice, + ModelUsageUnit, + NotFoundError, + NumericScore, + NumericScoreV1, + Observation, + ObservationLevel, + ObservationsView, + PricingTier, + PricingTierCondition, + PricingTierInput, + PricingTierOperator, + Score, + ScoreConfig, + ScoreDataType, + ScoreSource, + ScoreV1, + ScoreV1_Boolean, + ScoreV1_Categorical, + ScoreV1_Numeric, + Score_Boolean, + Score_Categorical, + Score_Numeric, + Session, + SessionWithTraces, + Trace, + TraceWithDetails, + TraceWithFullDetails, + UnauthorizedError, + Usage, + ) + from .dataset_items import ( + CreateDatasetItemRequest, + DeleteDatasetItemResponse, + PaginatedDatasetItems, + ) + from .dataset_run_items import CreateDatasetRunItemRequest, PaginatedDatasetRunItems + from .datasets import ( + CreateDatasetRequest, + DeleteDatasetRunResponse, + PaginatedDatasetRuns, + PaginatedDatasets, + ) + from .health import HealthResponse, ServiceUnavailableError + from .ingestion import ( + BaseEvent, + CreateEventBody, + CreateEventEvent, + CreateGenerationBody, + CreateGenerationEvent, + CreateObservationEvent, + CreateSpanBody, + CreateSpanEvent, + IngestionError, + IngestionEvent, + IngestionEvent_EventCreate, + IngestionEvent_GenerationCreate, + IngestionEvent_GenerationUpdate, + IngestionEvent_ObservationCreate, + IngestionEvent_ObservationUpdate, + IngestionEvent_ScoreCreate, + IngestionEvent_SdkLog, + IngestionEvent_SpanCreate, + IngestionEvent_SpanUpdate, + IngestionEvent_TraceCreate, + IngestionResponse, + IngestionSuccess, + IngestionUsage, + ObservationBody, + ObservationType, + OpenAiCompletionUsageSchema, + OpenAiResponseUsageSchema, + OpenAiUsage, + OptionalObservationBody, + ScoreBody, + ScoreEvent, + SdkLogBody, + SdkLogEvent, + TraceBody, + TraceEvent, + UpdateEventBody, + UpdateGenerationBody, + UpdateGenerationEvent, + UpdateObservationEvent, + UpdateSpanBody, + UpdateSpanEvent, + UsageDetails, + ) + from .llm_connections import ( + LlmAdapter, + LlmConnection, + PaginatedLlmConnections, + UpsertLlmConnectionRequest, + ) + from .media import ( + GetMediaResponse, + GetMediaUploadUrlRequest, + GetMediaUploadUrlResponse, + MediaContentType, + PatchMediaBody, + ) + from .metrics import MetricsResponse + from .models import CreateModelRequest, PaginatedModels + from .observations import Observations, ObservationsViews + from .opentelemetry import ( + OtelAttribute, + OtelAttributeValue, + OtelResource, + OtelResourceSpan, + OtelScope, + OtelScopeSpan, + OtelSpan, + OtelTraceResponse, + ) + from .organizations import ( + DeleteMembershipRequest, + MembershipDeletionResponse, + MembershipRequest, + MembershipResponse, + MembershipRole, + MembershipsResponse, + OrganizationApiKey, + OrganizationApiKeysResponse, + OrganizationProject, + OrganizationProjectsResponse, + ) + from .projects import ( + ApiKeyDeletionResponse, + ApiKeyList, + ApiKeyResponse, + ApiKeySummary, + Project, + ProjectDeletionResponse, + Projects, + ) + from .prompts import ( + BasePrompt, + ChatMessage, + ChatMessageWithPlaceholders, + ChatMessageWithPlaceholders_Chatmessage, + ChatMessageWithPlaceholders_Placeholder, + ChatPrompt, + CreateChatPromptRequest, + CreatePromptRequest, + CreatePromptRequest_Chat, + CreatePromptRequest_Text, + CreateTextPromptRequest, + PlaceholderMessage, + Prompt, + PromptMeta, + PromptMetaListResponse, + PromptType, + Prompt_Chat, + Prompt_Text, + TextPrompt, + ) + from .scim import ( + AuthenticationScheme, + BulkConfig, + EmptyResponse, + FilterConfig, + ResourceMeta, + ResourceType, + ResourceTypesResponse, + SchemaExtension, + SchemaResource, + SchemasResponse, + ScimEmail, + ScimFeatureSupport, + ScimName, + ScimUser, + ScimUsersListResponse, + ServiceProviderConfig, + UserMeta, + ) + from .score import CreateScoreRequest, CreateScoreResponse + from .score_configs import ( + CreateScoreConfigRequest, + ScoreConfigs, + UpdateScoreConfigRequest, + ) + from .score_v2 import ( + GetScoresResponse, + GetScoresResponseData, + GetScoresResponseDataBoolean, + GetScoresResponseDataCategorical, + GetScoresResponseDataNumeric, + GetScoresResponseData_Boolean, + GetScoresResponseData_Categorical, + GetScoresResponseData_Numeric, + GetScoresResponseTraceData, + ) + from .sessions import PaginatedSessions + from .trace import DeleteTraceResponse, Sort, Traces +_dynamic_imports: typing.Dict[str, str] = { + "AccessDeniedError": ".commons", + "AnnotationQueue": ".annotation_queues", + "AnnotationQueueAssignmentRequest": ".annotation_queues", + "AnnotationQueueItem": ".annotation_queues", + "AnnotationQueueObjectType": ".annotation_queues", + "AnnotationQueueStatus": ".annotation_queues", + "ApiKeyDeletionResponse": ".projects", + "ApiKeyList": ".projects", + "ApiKeyResponse": ".projects", + "ApiKeySummary": ".projects", + "AsyncLangfuseAPI": ".client", + "AuthenticationScheme": ".scim", + "BaseEvent": ".ingestion", + "BasePrompt": ".prompts", + "BaseScore": ".commons", + "BaseScoreV1": ".commons", + "BlobStorageExportFrequency": ".blob_storage_integrations", + "BlobStorageExportMode": ".blob_storage_integrations", + "BlobStorageIntegrationDeletionResponse": ".blob_storage_integrations", + "BlobStorageIntegrationFileType": ".blob_storage_integrations", + "BlobStorageIntegrationResponse": ".blob_storage_integrations", + "BlobStorageIntegrationType": ".blob_storage_integrations", + "BlobStorageIntegrationsResponse": ".blob_storage_integrations", + "BooleanScore": ".commons", + "BooleanScoreV1": ".commons", + "BulkConfig": ".scim", + "CategoricalScore": ".commons", + "CategoricalScoreV1": ".commons", + "ChatMessage": ".prompts", + "ChatMessageWithPlaceholders": ".prompts", + "ChatMessageWithPlaceholders_Chatmessage": ".prompts", + "ChatMessageWithPlaceholders_Placeholder": ".prompts", + "ChatPrompt": ".prompts", + "Comment": ".commons", + "CommentObjectType": ".commons", + "ConfigCategory": ".commons", + "CreateAnnotationQueueAssignmentResponse": ".annotation_queues", + "CreateAnnotationQueueItemRequest": ".annotation_queues", + "CreateAnnotationQueueRequest": ".annotation_queues", + "CreateBlobStorageIntegrationRequest": ".blob_storage_integrations", + "CreateChatPromptRequest": ".prompts", + "CreateCommentRequest": ".comments", + "CreateCommentResponse": ".comments", + "CreateDatasetItemRequest": ".dataset_items", + "CreateDatasetRequest": ".datasets", + "CreateDatasetRunItemRequest": ".dataset_run_items", + "CreateEventBody": ".ingestion", + "CreateEventEvent": ".ingestion", + "CreateGenerationBody": ".ingestion", + "CreateGenerationEvent": ".ingestion", + "CreateModelRequest": ".models", + "CreateObservationEvent": ".ingestion", + "CreatePromptRequest": ".prompts", + "CreatePromptRequest_Chat": ".prompts", + "CreatePromptRequest_Text": ".prompts", + "CreateScoreConfigRequest": ".score_configs", + "CreateScoreRequest": ".score", + "CreateScoreResponse": ".score", + "CreateScoreValue": ".commons", + "CreateSpanBody": ".ingestion", + "CreateSpanEvent": ".ingestion", + "CreateTextPromptRequest": ".prompts", + "Dataset": ".commons", + "DatasetItem": ".commons", + "DatasetRun": ".commons", + "DatasetRunItem": ".commons", + "DatasetRunWithItems": ".commons", + "DatasetStatus": ".commons", + "DeleteAnnotationQueueAssignmentResponse": ".annotation_queues", + "DeleteAnnotationQueueItemResponse": ".annotation_queues", + "DeleteDatasetItemResponse": ".dataset_items", + "DeleteDatasetRunResponse": ".datasets", + "DeleteMembershipRequest": ".organizations", + "DeleteTraceResponse": ".trace", + "EmptyResponse": ".scim", + "Error": ".commons", + "FilterConfig": ".scim", + "GetCommentsResponse": ".comments", + "GetMediaResponse": ".media", + "GetMediaUploadUrlRequest": ".media", + "GetMediaUploadUrlResponse": ".media", + "GetScoresResponse": ".score_v2", + "GetScoresResponseData": ".score_v2", + "GetScoresResponseDataBoolean": ".score_v2", + "GetScoresResponseDataCategorical": ".score_v2", + "GetScoresResponseDataNumeric": ".score_v2", + "GetScoresResponseData_Boolean": ".score_v2", + "GetScoresResponseData_Categorical": ".score_v2", + "GetScoresResponseData_Numeric": ".score_v2", + "GetScoresResponseTraceData": ".score_v2", + "HealthResponse": ".health", + "IngestionError": ".ingestion", + "IngestionEvent": ".ingestion", + "IngestionEvent_EventCreate": ".ingestion", + "IngestionEvent_GenerationCreate": ".ingestion", + "IngestionEvent_GenerationUpdate": ".ingestion", + "IngestionEvent_ObservationCreate": ".ingestion", + "IngestionEvent_ObservationUpdate": ".ingestion", + "IngestionEvent_ScoreCreate": ".ingestion", + "IngestionEvent_SdkLog": ".ingestion", + "IngestionEvent_SpanCreate": ".ingestion", + "IngestionEvent_SpanUpdate": ".ingestion", + "IngestionEvent_TraceCreate": ".ingestion", + "IngestionResponse": ".ingestion", + "IngestionSuccess": ".ingestion", + "IngestionUsage": ".ingestion", + "LangfuseAPI": ".client", + "LlmAdapter": ".llm_connections", + "LlmConnection": ".llm_connections", + "MapValue": ".commons", + "MediaContentType": ".media", + "MembershipDeletionResponse": ".organizations", + "MembershipRequest": ".organizations", + "MembershipResponse": ".organizations", + "MembershipRole": ".organizations", + "MembershipsResponse": ".organizations", + "MethodNotAllowedError": ".commons", + "MetricsResponse": ".metrics", + "Model": ".commons", + "ModelPrice": ".commons", + "ModelUsageUnit": ".commons", + "NotFoundError": ".commons", + "NumericScore": ".commons", + "NumericScoreV1": ".commons", + "Observation": ".commons", + "ObservationBody": ".ingestion", + "ObservationLevel": ".commons", + "ObservationType": ".ingestion", + "Observations": ".observations", + "ObservationsView": ".commons", + "ObservationsViews": ".observations", + "OpenAiCompletionUsageSchema": ".ingestion", + "OpenAiResponseUsageSchema": ".ingestion", + "OpenAiUsage": ".ingestion", + "OptionalObservationBody": ".ingestion", + "OrganizationApiKey": ".organizations", + "OrganizationApiKeysResponse": ".organizations", + "OrganizationProject": ".organizations", + "OrganizationProjectsResponse": ".organizations", + "OtelAttribute": ".opentelemetry", + "OtelAttributeValue": ".opentelemetry", + "OtelResource": ".opentelemetry", + "OtelResourceSpan": ".opentelemetry", + "OtelScope": ".opentelemetry", + "OtelScopeSpan": ".opentelemetry", + "OtelSpan": ".opentelemetry", + "OtelTraceResponse": ".opentelemetry", + "PaginatedAnnotationQueueItems": ".annotation_queues", + "PaginatedAnnotationQueues": ".annotation_queues", + "PaginatedDatasetItems": ".dataset_items", + "PaginatedDatasetRunItems": ".dataset_run_items", + "PaginatedDatasetRuns": ".datasets", + "PaginatedDatasets": ".datasets", + "PaginatedLlmConnections": ".llm_connections", + "PaginatedModels": ".models", + "PaginatedSessions": ".sessions", + "PatchMediaBody": ".media", + "PlaceholderMessage": ".prompts", + "PricingTier": ".commons", + "PricingTierCondition": ".commons", + "PricingTierInput": ".commons", + "PricingTierOperator": ".commons", + "Project": ".projects", + "ProjectDeletionResponse": ".projects", + "Projects": ".projects", + "Prompt": ".prompts", + "PromptMeta": ".prompts", + "PromptMetaListResponse": ".prompts", + "PromptType": ".prompts", + "Prompt_Chat": ".prompts", + "Prompt_Text": ".prompts", + "ResourceMeta": ".scim", + "ResourceType": ".scim", + "ResourceTypesResponse": ".scim", + "SchemaExtension": ".scim", + "SchemaResource": ".scim", + "SchemasResponse": ".scim", + "ScimEmail": ".scim", + "ScimFeatureSupport": ".scim", + "ScimName": ".scim", + "ScimUser": ".scim", + "ScimUsersListResponse": ".scim", + "Score": ".commons", + "ScoreBody": ".ingestion", + "ScoreConfig": ".commons", + "ScoreConfigs": ".score_configs", + "ScoreDataType": ".commons", + "ScoreEvent": ".ingestion", + "ScoreSource": ".commons", + "ScoreV1": ".commons", + "ScoreV1_Boolean": ".commons", + "ScoreV1_Categorical": ".commons", + "ScoreV1_Numeric": ".commons", + "Score_Boolean": ".commons", + "Score_Categorical": ".commons", + "Score_Numeric": ".commons", + "SdkLogBody": ".ingestion", + "SdkLogEvent": ".ingestion", + "ServiceProviderConfig": ".scim", + "ServiceUnavailableError": ".health", + "Session": ".commons", + "SessionWithTraces": ".commons", + "Sort": ".trace", + "TextPrompt": ".prompts", + "Trace": ".commons", + "TraceBody": ".ingestion", + "TraceEvent": ".ingestion", + "TraceWithDetails": ".commons", + "TraceWithFullDetails": ".commons", + "Traces": ".trace", + "UnauthorizedError": ".commons", + "UpdateAnnotationQueueItemRequest": ".annotation_queues", + "UpdateEventBody": ".ingestion", + "UpdateGenerationBody": ".ingestion", + "UpdateGenerationEvent": ".ingestion", + "UpdateObservationEvent": ".ingestion", + "UpdateScoreConfigRequest": ".score_configs", + "UpdateSpanBody": ".ingestion", + "UpdateSpanEvent": ".ingestion", + "UpsertLlmConnectionRequest": ".llm_connections", + "Usage": ".commons", + "UsageDetails": ".ingestion", + "UserMeta": ".scim", + "annotation_queues": ".annotation_queues", + "blob_storage_integrations": ".blob_storage_integrations", + "comments": ".comments", + "commons": ".commons", + "dataset_items": ".dataset_items", + "dataset_run_items": ".dataset_run_items", + "datasets": ".datasets", + "health": ".health", + "ingestion": ".ingestion", + "llm_connections": ".llm_connections", + "media": ".media", + "metrics": ".metrics", + "models": ".models", + "observations": ".observations", + "opentelemetry": ".opentelemetry", + "organizations": ".organizations", + "projects": ".projects", + "prompt_version": ".prompt_version", + "prompts": ".prompts", + "scim": ".scim", + "score": ".score", + "score_configs": ".score_configs", + "score_v2": ".score_v2", + "sessions": ".sessions", + "trace": ".trace", + "utils": ".utils", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + __all__ = [ "AccessDeniedError", @@ -261,6 +572,7 @@ "ApiKeyList", "ApiKeyResponse", "ApiKeySummary", + "AsyncLangfuseAPI", "AuthenticationScheme", "BaseEvent", "BasePrompt", @@ -356,6 +668,7 @@ "IngestionResponse", "IngestionSuccess", "IngestionUsage", + "LangfuseAPI", "LlmAdapter", "LlmConnection", "MapValue", @@ -494,7 +807,7 @@ "scim", "score", "score_configs", - "score_v_2", + "score_v2", "sessions", "trace", "utils", diff --git a/langfuse/api/annotation_queues/__init__.py b/langfuse/api/annotation_queues/__init__.py new file mode 100644 index 000000000..119661e05 --- /dev/null +++ b/langfuse/api/annotation_queues/__init__.py @@ -0,0 +1,82 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + AnnotationQueue, + AnnotationQueueAssignmentRequest, + AnnotationQueueItem, + AnnotationQueueObjectType, + AnnotationQueueStatus, + CreateAnnotationQueueAssignmentResponse, + CreateAnnotationQueueItemRequest, + CreateAnnotationQueueRequest, + DeleteAnnotationQueueAssignmentResponse, + DeleteAnnotationQueueItemResponse, + PaginatedAnnotationQueueItems, + PaginatedAnnotationQueues, + UpdateAnnotationQueueItemRequest, + ) +_dynamic_imports: typing.Dict[str, str] = { + "AnnotationQueue": ".types", + "AnnotationQueueAssignmentRequest": ".types", + "AnnotationQueueItem": ".types", + "AnnotationQueueObjectType": ".types", + "AnnotationQueueStatus": ".types", + "CreateAnnotationQueueAssignmentResponse": ".types", + "CreateAnnotationQueueItemRequest": ".types", + "CreateAnnotationQueueRequest": ".types", + "DeleteAnnotationQueueAssignmentResponse": ".types", + "DeleteAnnotationQueueItemResponse": ".types", + "PaginatedAnnotationQueueItems": ".types", + "PaginatedAnnotationQueues": ".types", + "UpdateAnnotationQueueItemRequest": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "AnnotationQueue", + "AnnotationQueueAssignmentRequest", + "AnnotationQueueItem", + "AnnotationQueueObjectType", + "AnnotationQueueStatus", + "CreateAnnotationQueueAssignmentResponse", + "CreateAnnotationQueueItemRequest", + "CreateAnnotationQueueRequest", + "DeleteAnnotationQueueAssignmentResponse", + "DeleteAnnotationQueueItemResponse", + "PaginatedAnnotationQueueItems", + "PaginatedAnnotationQueues", + "UpdateAnnotationQueueItemRequest", +] diff --git a/langfuse/api/annotation_queues/client.py b/langfuse/api/annotation_queues/client.py new file mode 100644 index 000000000..e4ab29173 --- /dev/null +++ b/langfuse/api/annotation_queues/client.py @@ -0,0 +1,1109 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawAnnotationQueuesClient, RawAnnotationQueuesClient +from .types.annotation_queue import AnnotationQueue +from .types.annotation_queue_item import AnnotationQueueItem +from .types.annotation_queue_object_type import AnnotationQueueObjectType +from .types.annotation_queue_status import AnnotationQueueStatus +from .types.create_annotation_queue_assignment_response import ( + CreateAnnotationQueueAssignmentResponse, +) +from .types.delete_annotation_queue_assignment_response import ( + DeleteAnnotationQueueAssignmentResponse, +) +from .types.delete_annotation_queue_item_response import ( + DeleteAnnotationQueueItemResponse, +) +from .types.paginated_annotation_queue_items import PaginatedAnnotationQueueItems +from .types.paginated_annotation_queues import PaginatedAnnotationQueues + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class AnnotationQueuesClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawAnnotationQueuesClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawAnnotationQueuesClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawAnnotationQueuesClient + """ + return self._raw_client + + def list_queues( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedAnnotationQueues: + """ + Get all annotation queues + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedAnnotationQueues + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.annotation_queues.list_queues() + """ + _response = self._raw_client.list_queues( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + def create_queue( + self, + *, + name: str, + score_config_ids: typing.Sequence[str], + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AnnotationQueue: + """ + Create an annotation queue + + Parameters + ---------- + name : str + + score_config_ids : typing.Sequence[str] + + description : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AnnotationQueue + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.annotation_queues.create_queue( + name="name", + score_config_ids=["scoreConfigIds", "scoreConfigIds"], + ) + """ + _response = self._raw_client.create_queue( + name=name, + score_config_ids=score_config_ids, + description=description, + request_options=request_options, + ) + return _response.data + + def get_queue( + self, queue_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AnnotationQueue: + """ + Get an annotation queue by ID + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AnnotationQueue + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.annotation_queues.get_queue( + queue_id="queueId", + ) + """ + _response = self._raw_client.get_queue( + queue_id, request_options=request_options + ) + return _response.data + + def list_queue_items( + self, + queue_id: str, + *, + status: typing.Optional[AnnotationQueueStatus] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedAnnotationQueueItems: + """ + Get items for a specific annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + status : typing.Optional[AnnotationQueueStatus] + Filter by status + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedAnnotationQueueItems + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.annotation_queues.list_queue_items( + queue_id="queueId", + ) + """ + _response = self._raw_client.list_queue_items( + queue_id, + status=status, + page=page, + limit=limit, + request_options=request_options, + ) + return _response.data + + def get_queue_item( + self, + queue_id: str, + item_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AnnotationQueueItem: + """ + Get a specific item from an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AnnotationQueueItem + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.annotation_queues.get_queue_item( + queue_id="queueId", + item_id="itemId", + ) + """ + _response = self._raw_client.get_queue_item( + queue_id, item_id, request_options=request_options + ) + return _response.data + + def create_queue_item( + self, + queue_id: str, + *, + object_id: str, + object_type: AnnotationQueueObjectType, + status: typing.Optional[AnnotationQueueStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AnnotationQueueItem: + """ + Add an item to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + object_id : str + + object_type : AnnotationQueueObjectType + + status : typing.Optional[AnnotationQueueStatus] + Defaults to PENDING for new queue items + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AnnotationQueueItem + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.annotation_queues.create_queue_item( + queue_id="queueId", + object_id="objectId", + object_type="TRACE", + ) + """ + _response = self._raw_client.create_queue_item( + queue_id, + object_id=object_id, + object_type=object_type, + status=status, + request_options=request_options, + ) + return _response.data + + def update_queue_item( + self, + queue_id: str, + item_id: str, + *, + status: typing.Optional[AnnotationQueueStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AnnotationQueueItem: + """ + Update an annotation queue item + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + status : typing.Optional[AnnotationQueueStatus] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AnnotationQueueItem + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.annotation_queues.update_queue_item( + queue_id="queueId", + item_id="itemId", + ) + """ + _response = self._raw_client.update_queue_item( + queue_id, item_id, status=status, request_options=request_options + ) + return _response.data + + def delete_queue_item( + self, + queue_id: str, + item_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> DeleteAnnotationQueueItemResponse: + """ + Remove an item from an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteAnnotationQueueItemResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.annotation_queues.delete_queue_item( + queue_id="queueId", + item_id="itemId", + ) + """ + _response = self._raw_client.delete_queue_item( + queue_id, item_id, request_options=request_options + ) + return _response.data + + def create_queue_assignment( + self, + queue_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> CreateAnnotationQueueAssignmentResponse: + """ + Create an assignment for a user to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CreateAnnotationQueueAssignmentResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.annotation_queues.create_queue_assignment( + queue_id="queueId", + user_id="userId", + ) + """ + _response = self._raw_client.create_queue_assignment( + queue_id, user_id=user_id, request_options=request_options + ) + return _response.data + + def delete_queue_assignment( + self, + queue_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> DeleteAnnotationQueueAssignmentResponse: + """ + Delete an assignment for a user to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteAnnotationQueueAssignmentResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.annotation_queues.delete_queue_assignment( + queue_id="queueId", + user_id="userId", + ) + """ + _response = self._raw_client.delete_queue_assignment( + queue_id, user_id=user_id, request_options=request_options + ) + return _response.data + + +class AsyncAnnotationQueuesClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawAnnotationQueuesClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawAnnotationQueuesClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawAnnotationQueuesClient + """ + return self._raw_client + + async def list_queues( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedAnnotationQueues: + """ + Get all annotation queues + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedAnnotationQueues + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.annotation_queues.list_queues() + + + asyncio.run(main()) + """ + _response = await self._raw_client.list_queues( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + async def create_queue( + self, + *, + name: str, + score_config_ids: typing.Sequence[str], + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AnnotationQueue: + """ + Create an annotation queue + + Parameters + ---------- + name : str + + score_config_ids : typing.Sequence[str] + + description : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AnnotationQueue + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.annotation_queues.create_queue( + name="name", + score_config_ids=["scoreConfigIds", "scoreConfigIds"], + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create_queue( + name=name, + score_config_ids=score_config_ids, + description=description, + request_options=request_options, + ) + return _response.data + + async def get_queue( + self, queue_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AnnotationQueue: + """ + Get an annotation queue by ID + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AnnotationQueue + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.annotation_queues.get_queue( + queue_id="queueId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_queue( + queue_id, request_options=request_options + ) + return _response.data + + async def list_queue_items( + self, + queue_id: str, + *, + status: typing.Optional[AnnotationQueueStatus] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedAnnotationQueueItems: + """ + Get items for a specific annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + status : typing.Optional[AnnotationQueueStatus] + Filter by status + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedAnnotationQueueItems + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.annotation_queues.list_queue_items( + queue_id="queueId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.list_queue_items( + queue_id, + status=status, + page=page, + limit=limit, + request_options=request_options, + ) + return _response.data + + async def get_queue_item( + self, + queue_id: str, + item_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AnnotationQueueItem: + """ + Get a specific item from an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AnnotationQueueItem + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.annotation_queues.get_queue_item( + queue_id="queueId", + item_id="itemId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_queue_item( + queue_id, item_id, request_options=request_options + ) + return _response.data + + async def create_queue_item( + self, + queue_id: str, + *, + object_id: str, + object_type: AnnotationQueueObjectType, + status: typing.Optional[AnnotationQueueStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AnnotationQueueItem: + """ + Add an item to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + object_id : str + + object_type : AnnotationQueueObjectType + + status : typing.Optional[AnnotationQueueStatus] + Defaults to PENDING for new queue items + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AnnotationQueueItem + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.annotation_queues.create_queue_item( + queue_id="queueId", + object_id="objectId", + object_type="TRACE", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create_queue_item( + queue_id, + object_id=object_id, + object_type=object_type, + status=status, + request_options=request_options, + ) + return _response.data + + async def update_queue_item( + self, + queue_id: str, + item_id: str, + *, + status: typing.Optional[AnnotationQueueStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AnnotationQueueItem: + """ + Update an annotation queue item + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + status : typing.Optional[AnnotationQueueStatus] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AnnotationQueueItem + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.annotation_queues.update_queue_item( + queue_id="queueId", + item_id="itemId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.update_queue_item( + queue_id, item_id, status=status, request_options=request_options + ) + return _response.data + + async def delete_queue_item( + self, + queue_id: str, + item_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> DeleteAnnotationQueueItemResponse: + """ + Remove an item from an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteAnnotationQueueItemResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.annotation_queues.delete_queue_item( + queue_id="queueId", + item_id="itemId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete_queue_item( + queue_id, item_id, request_options=request_options + ) + return _response.data + + async def create_queue_assignment( + self, + queue_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> CreateAnnotationQueueAssignmentResponse: + """ + Create an assignment for a user to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CreateAnnotationQueueAssignmentResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.annotation_queues.create_queue_assignment( + queue_id="queueId", + user_id="userId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create_queue_assignment( + queue_id, user_id=user_id, request_options=request_options + ) + return _response.data + + async def delete_queue_assignment( + self, + queue_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> DeleteAnnotationQueueAssignmentResponse: + """ + Delete an assignment for a user to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteAnnotationQueueAssignmentResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.annotation_queues.delete_queue_assignment( + queue_id="queueId", + user_id="userId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete_queue_assignment( + queue_id, user_id=user_id, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/annotation_queues/raw_client.py b/langfuse/api/annotation_queues/raw_client.py new file mode 100644 index 000000000..451095061 --- /dev/null +++ b/langfuse/api/annotation_queues/raw_client.py @@ -0,0 +1,2288 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.annotation_queue import AnnotationQueue +from .types.annotation_queue_item import AnnotationQueueItem +from .types.annotation_queue_object_type import AnnotationQueueObjectType +from .types.annotation_queue_status import AnnotationQueueStatus +from .types.create_annotation_queue_assignment_response import ( + CreateAnnotationQueueAssignmentResponse, +) +from .types.delete_annotation_queue_assignment_response import ( + DeleteAnnotationQueueAssignmentResponse, +) +from .types.delete_annotation_queue_item_response import ( + DeleteAnnotationQueueItemResponse, +) +from .types.paginated_annotation_queue_items import PaginatedAnnotationQueueItems +from .types.paginated_annotation_queues import PaginatedAnnotationQueues + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawAnnotationQueuesClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def list_queues( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[PaginatedAnnotationQueues]: + """ + Get all annotation queues + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[PaginatedAnnotationQueues] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/annotation-queues", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedAnnotationQueues, + parse_obj_as( + type_=PaginatedAnnotationQueues, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def create_queue( + self, + *, + name: str, + score_config_ids: typing.Sequence[str], + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[AnnotationQueue]: + """ + Create an annotation queue + + Parameters + ---------- + name : str + + score_config_ids : typing.Sequence[str] + + description : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[AnnotationQueue] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/annotation-queues", + method="POST", + json={ + "name": name, + "description": description, + "scoreConfigIds": score_config_ids, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + AnnotationQueue, + parse_obj_as( + type_=AnnotationQueue, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_queue( + self, queue_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[AnnotationQueue]: + """ + Get an annotation queue by ID + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[AnnotationQueue] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + AnnotationQueue, + parse_obj_as( + type_=AnnotationQueue, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def list_queue_items( + self, + queue_id: str, + *, + status: typing.Optional[AnnotationQueueStatus] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[PaginatedAnnotationQueueItems]: + """ + Get items for a specific annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + status : typing.Optional[AnnotationQueueStatus] + Filter by status + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[PaginatedAnnotationQueueItems] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items", + method="GET", + params={ + "status": status, + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedAnnotationQueueItems, + parse_obj_as( + type_=PaginatedAnnotationQueueItems, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_queue_item( + self, + queue_id: str, + item_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[AnnotationQueueItem]: + """ + Get a specific item from an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[AnnotationQueueItem] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + AnnotationQueueItem, + parse_obj_as( + type_=AnnotationQueueItem, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def create_queue_item( + self, + queue_id: str, + *, + object_id: str, + object_type: AnnotationQueueObjectType, + status: typing.Optional[AnnotationQueueStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[AnnotationQueueItem]: + """ + Add an item to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + object_id : str + + object_type : AnnotationQueueObjectType + + status : typing.Optional[AnnotationQueueStatus] + Defaults to PENDING for new queue items + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[AnnotationQueueItem] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items", + method="POST", + json={ + "objectId": object_id, + "objectType": object_type, + "status": status, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + AnnotationQueueItem, + parse_obj_as( + type_=AnnotationQueueItem, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def update_queue_item( + self, + queue_id: str, + item_id: str, + *, + status: typing.Optional[AnnotationQueueStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[AnnotationQueueItem]: + """ + Update an annotation queue item + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + status : typing.Optional[AnnotationQueueStatus] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[AnnotationQueueItem] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", + method="PATCH", + json={ + "status": status, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + AnnotationQueueItem, + parse_obj_as( + type_=AnnotationQueueItem, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete_queue_item( + self, + queue_id: str, + item_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[DeleteAnnotationQueueItemResponse]: + """ + Remove an item from an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DeleteAnnotationQueueItemResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteAnnotationQueueItemResponse, + parse_obj_as( + type_=DeleteAnnotationQueueItemResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def create_queue_assignment( + self, + queue_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[CreateAnnotationQueueAssignmentResponse]: + """ + Create an assignment for a user to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[CreateAnnotationQueueAssignmentResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/assignments", + method="POST", + json={ + "userId": user_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CreateAnnotationQueueAssignmentResponse, + parse_obj_as( + type_=CreateAnnotationQueueAssignmentResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete_queue_assignment( + self, + queue_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[DeleteAnnotationQueueAssignmentResponse]: + """ + Delete an assignment for a user to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DeleteAnnotationQueueAssignmentResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/assignments", + method="DELETE", + json={ + "userId": user_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteAnnotationQueueAssignmentResponse, + parse_obj_as( + type_=DeleteAnnotationQueueAssignmentResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawAnnotationQueuesClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list_queues( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[PaginatedAnnotationQueues]: + """ + Get all annotation queues + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[PaginatedAnnotationQueues] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/annotation-queues", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedAnnotationQueues, + parse_obj_as( + type_=PaginatedAnnotationQueues, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def create_queue( + self, + *, + name: str, + score_config_ids: typing.Sequence[str], + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[AnnotationQueue]: + """ + Create an annotation queue + + Parameters + ---------- + name : str + + score_config_ids : typing.Sequence[str] + + description : typing.Optional[str] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[AnnotationQueue] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/annotation-queues", + method="POST", + json={ + "name": name, + "description": description, + "scoreConfigIds": score_config_ids, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + AnnotationQueue, + parse_obj_as( + type_=AnnotationQueue, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_queue( + self, queue_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[AnnotationQueue]: + """ + Get an annotation queue by ID + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[AnnotationQueue] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + AnnotationQueue, + parse_obj_as( + type_=AnnotationQueue, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def list_queue_items( + self, + queue_id: str, + *, + status: typing.Optional[AnnotationQueueStatus] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[PaginatedAnnotationQueueItems]: + """ + Get items for a specific annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + status : typing.Optional[AnnotationQueueStatus] + Filter by status + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[PaginatedAnnotationQueueItems] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items", + method="GET", + params={ + "status": status, + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedAnnotationQueueItems, + parse_obj_as( + type_=PaginatedAnnotationQueueItems, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_queue_item( + self, + queue_id: str, + item_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[AnnotationQueueItem]: + """ + Get a specific item from an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[AnnotationQueueItem] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + AnnotationQueueItem, + parse_obj_as( + type_=AnnotationQueueItem, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def create_queue_item( + self, + queue_id: str, + *, + object_id: str, + object_type: AnnotationQueueObjectType, + status: typing.Optional[AnnotationQueueStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[AnnotationQueueItem]: + """ + Add an item to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + object_id : str + + object_type : AnnotationQueueObjectType + + status : typing.Optional[AnnotationQueueStatus] + Defaults to PENDING for new queue items + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[AnnotationQueueItem] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items", + method="POST", + json={ + "objectId": object_id, + "objectType": object_type, + "status": status, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + AnnotationQueueItem, + parse_obj_as( + type_=AnnotationQueueItem, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def update_queue_item( + self, + queue_id: str, + item_id: str, + *, + status: typing.Optional[AnnotationQueueStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[AnnotationQueueItem]: + """ + Update an annotation queue item + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + status : typing.Optional[AnnotationQueueStatus] + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[AnnotationQueueItem] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", + method="PATCH", + json={ + "status": status, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + AnnotationQueueItem, + parse_obj_as( + type_=AnnotationQueueItem, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete_queue_item( + self, + queue_id: str, + item_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[DeleteAnnotationQueueItemResponse]: + """ + Remove an item from an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + item_id : str + The unique identifier of the annotation queue item + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DeleteAnnotationQueueItemResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteAnnotationQueueItemResponse, + parse_obj_as( + type_=DeleteAnnotationQueueItemResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def create_queue_assignment( + self, + queue_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[CreateAnnotationQueueAssignmentResponse]: + """ + Create an assignment for a user to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[CreateAnnotationQueueAssignmentResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/assignments", + method="POST", + json={ + "userId": user_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CreateAnnotationQueueAssignmentResponse, + parse_obj_as( + type_=CreateAnnotationQueueAssignmentResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete_queue_assignment( + self, + queue_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[DeleteAnnotationQueueAssignmentResponse]: + """ + Delete an assignment for a user to an annotation queue + + Parameters + ---------- + queue_id : str + The unique identifier of the annotation queue + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DeleteAnnotationQueueAssignmentResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/assignments", + method="DELETE", + json={ + "userId": user_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteAnnotationQueueAssignmentResponse, + parse_obj_as( + type_=DeleteAnnotationQueueAssignmentResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/annotation_queues/types/__init__.py b/langfuse/api/annotation_queues/types/__init__.py new file mode 100644 index 000000000..0d34bb763 --- /dev/null +++ b/langfuse/api/annotation_queues/types/__init__.py @@ -0,0 +1,84 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .annotation_queue import AnnotationQueue + from .annotation_queue_assignment_request import AnnotationQueueAssignmentRequest + from .annotation_queue_item import AnnotationQueueItem + from .annotation_queue_object_type import AnnotationQueueObjectType + from .annotation_queue_status import AnnotationQueueStatus + from .create_annotation_queue_assignment_response import ( + CreateAnnotationQueueAssignmentResponse, + ) + from .create_annotation_queue_item_request import CreateAnnotationQueueItemRequest + from .create_annotation_queue_request import CreateAnnotationQueueRequest + from .delete_annotation_queue_assignment_response import ( + DeleteAnnotationQueueAssignmentResponse, + ) + from .delete_annotation_queue_item_response import DeleteAnnotationQueueItemResponse + from .paginated_annotation_queue_items import PaginatedAnnotationQueueItems + from .paginated_annotation_queues import PaginatedAnnotationQueues + from .update_annotation_queue_item_request import UpdateAnnotationQueueItemRequest +_dynamic_imports: typing.Dict[str, str] = { + "AnnotationQueue": ".annotation_queue", + "AnnotationQueueAssignmentRequest": ".annotation_queue_assignment_request", + "AnnotationQueueItem": ".annotation_queue_item", + "AnnotationQueueObjectType": ".annotation_queue_object_type", + "AnnotationQueueStatus": ".annotation_queue_status", + "CreateAnnotationQueueAssignmentResponse": ".create_annotation_queue_assignment_response", + "CreateAnnotationQueueItemRequest": ".create_annotation_queue_item_request", + "CreateAnnotationQueueRequest": ".create_annotation_queue_request", + "DeleteAnnotationQueueAssignmentResponse": ".delete_annotation_queue_assignment_response", + "DeleteAnnotationQueueItemResponse": ".delete_annotation_queue_item_response", + "PaginatedAnnotationQueueItems": ".paginated_annotation_queue_items", + "PaginatedAnnotationQueues": ".paginated_annotation_queues", + "UpdateAnnotationQueueItemRequest": ".update_annotation_queue_item_request", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "AnnotationQueue", + "AnnotationQueueAssignmentRequest", + "AnnotationQueueItem", + "AnnotationQueueObjectType", + "AnnotationQueueStatus", + "CreateAnnotationQueueAssignmentResponse", + "CreateAnnotationQueueItemRequest", + "CreateAnnotationQueueRequest", + "DeleteAnnotationQueueAssignmentResponse", + "DeleteAnnotationQueueItemResponse", + "PaginatedAnnotationQueueItems", + "PaginatedAnnotationQueues", + "UpdateAnnotationQueueItemRequest", +] diff --git a/langfuse/api/annotation_queues/types/annotation_queue.py b/langfuse/api/annotation_queues/types/annotation_queue.py new file mode 100644 index 000000000..40048fcba --- /dev/null +++ b/langfuse/api/annotation_queues/types/annotation_queue.py @@ -0,0 +1,35 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class AnnotationQueue(UniversalBaseModel): + id: str + name: str + description: typing.Optional[str] = None + score_config_ids: typing_extensions.Annotated[ + typing.List[str], FieldMetadata(alias="scoreConfigIds") + ] + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/annotation_queues/types/annotation_queue_assignment_request.py b/langfuse/api/annotation_queues/types/annotation_queue_assignment_request.py new file mode 100644 index 000000000..33da0d3e2 --- /dev/null +++ b/langfuse/api/annotation_queues/types/annotation_queue_assignment_request.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class AnnotationQueueAssignmentRequest(UniversalBaseModel): + user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/annotation_queues/types/annotation_queue_item.py b/langfuse/api/annotation_queues/types/annotation_queue_item.py new file mode 100644 index 000000000..51ee9761a --- /dev/null +++ b/langfuse/api/annotation_queues/types/annotation_queue_item.py @@ -0,0 +1,41 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .annotation_queue_object_type import AnnotationQueueObjectType +from .annotation_queue_status import AnnotationQueueStatus + + +class AnnotationQueueItem(UniversalBaseModel): + id: str + queue_id: typing_extensions.Annotated[str, FieldMetadata(alias="queueId")] + object_id: typing_extensions.Annotated[str, FieldMetadata(alias="objectId")] + object_type: typing_extensions.Annotated[ + AnnotationQueueObjectType, FieldMetadata(alias="objectType") + ] + status: AnnotationQueueStatus + completed_at: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="completedAt") + ] = None + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/annotation_queues/types/annotation_queue_object_type.py b/langfuse/api/annotation_queues/types/annotation_queue_object_type.py new file mode 100644 index 000000000..8f95334b0 --- /dev/null +++ b/langfuse/api/annotation_queues/types/annotation_queue_object_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +AnnotationQueueObjectType = typing.Union[ + typing.Literal["TRACE", "OBSERVATION", "SESSION"], typing.Any +] diff --git a/langfuse/api/annotation_queues/types/annotation_queue_status.py b/langfuse/api/annotation_queues/types/annotation_queue_status.py new file mode 100644 index 000000000..0a732adbc --- /dev/null +++ b/langfuse/api/annotation_queues/types/annotation_queue_status.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +AnnotationQueueStatus = typing.Union[typing.Literal["PENDING", "COMPLETED"], typing.Any] diff --git a/langfuse/api/annotation_queues/types/create_annotation_queue_assignment_response.py b/langfuse/api/annotation_queues/types/create_annotation_queue_assignment_response.py new file mode 100644 index 000000000..49b8cb216 --- /dev/null +++ b/langfuse/api/annotation_queues/types/create_annotation_queue_assignment_response.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class CreateAnnotationQueueAssignmentResponse(UniversalBaseModel): + user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] + queue_id: typing_extensions.Annotated[str, FieldMetadata(alias="queueId")] + project_id: typing_extensions.Annotated[str, FieldMetadata(alias="projectId")] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/annotation_queues/types/create_annotation_queue_item_request.py b/langfuse/api/annotation_queues/types/create_annotation_queue_item_request.py new file mode 100644 index 000000000..8a029385e --- /dev/null +++ b/langfuse/api/annotation_queues/types/create_annotation_queue_item_request.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .annotation_queue_object_type import AnnotationQueueObjectType +from .annotation_queue_status import AnnotationQueueStatus + + +class CreateAnnotationQueueItemRequest(UniversalBaseModel): + object_id: typing_extensions.Annotated[str, FieldMetadata(alias="objectId")] + object_type: typing_extensions.Annotated[ + AnnotationQueueObjectType, FieldMetadata(alias="objectType") + ] + status: typing.Optional[AnnotationQueueStatus] = pydantic.Field(default=None) + """ + Defaults to PENDING for new queue items + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/annotation_queues/types/create_annotation_queue_request.py b/langfuse/api/annotation_queues/types/create_annotation_queue_request.py new file mode 100644 index 000000000..72e0ba29f --- /dev/null +++ b/langfuse/api/annotation_queues/types/create_annotation_queue_request.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class CreateAnnotationQueueRequest(UniversalBaseModel): + name: str + description: typing.Optional[str] = None + score_config_ids: typing_extensions.Annotated[ + typing.List[str], FieldMetadata(alias="scoreConfigIds") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/annotation_queues/types/delete_annotation_queue_assignment_response.py b/langfuse/api/annotation_queues/types/delete_annotation_queue_assignment_response.py new file mode 100644 index 000000000..ae87e50a4 --- /dev/null +++ b/langfuse/api/annotation_queues/types/delete_annotation_queue_assignment_response.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class DeleteAnnotationQueueAssignmentResponse(UniversalBaseModel): + success: bool + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/annotation_queues/types/delete_annotation_queue_item_response.py b/langfuse/api/annotation_queues/types/delete_annotation_queue_item_response.py new file mode 100644 index 000000000..14b295335 --- /dev/null +++ b/langfuse/api/annotation_queues/types/delete_annotation_queue_item_response.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class DeleteAnnotationQueueItemResponse(UniversalBaseModel): + success: bool + message: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/annotation_queues/types/paginated_annotation_queue_items.py b/langfuse/api/annotation_queues/types/paginated_annotation_queue_items.py new file mode 100644 index 000000000..ace3188fe --- /dev/null +++ b/langfuse/api/annotation_queues/types/paginated_annotation_queue_items.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse +from .annotation_queue_item import AnnotationQueueItem + + +class PaginatedAnnotationQueueItems(UniversalBaseModel): + data: typing.List[AnnotationQueueItem] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/annotation_queues/types/paginated_annotation_queues.py b/langfuse/api/annotation_queues/types/paginated_annotation_queues.py new file mode 100644 index 000000000..6e9b36b79 --- /dev/null +++ b/langfuse/api/annotation_queues/types/paginated_annotation_queues.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse +from .annotation_queue import AnnotationQueue + + +class PaginatedAnnotationQueues(UniversalBaseModel): + data: typing.List[AnnotationQueue] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/annotation_queues/types/update_annotation_queue_item_request.py b/langfuse/api/annotation_queues/types/update_annotation_queue_item_request.py new file mode 100644 index 000000000..eef9846af --- /dev/null +++ b/langfuse/api/annotation_queues/types/update_annotation_queue_item_request.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .annotation_queue_status import AnnotationQueueStatus + + +class UpdateAnnotationQueueItemRequest(UniversalBaseModel): + status: typing.Optional[AnnotationQueueStatus] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/blob_storage_integrations/__init__.py b/langfuse/api/blob_storage_integrations/__init__.py new file mode 100644 index 000000000..abd0d9e84 --- /dev/null +++ b/langfuse/api/blob_storage_integrations/__init__.py @@ -0,0 +1,67 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + BlobStorageExportFrequency, + BlobStorageExportMode, + BlobStorageIntegrationDeletionResponse, + BlobStorageIntegrationFileType, + BlobStorageIntegrationResponse, + BlobStorageIntegrationType, + BlobStorageIntegrationsResponse, + CreateBlobStorageIntegrationRequest, + ) +_dynamic_imports: typing.Dict[str, str] = { + "BlobStorageExportFrequency": ".types", + "BlobStorageExportMode": ".types", + "BlobStorageIntegrationDeletionResponse": ".types", + "BlobStorageIntegrationFileType": ".types", + "BlobStorageIntegrationResponse": ".types", + "BlobStorageIntegrationType": ".types", + "BlobStorageIntegrationsResponse": ".types", + "CreateBlobStorageIntegrationRequest": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "BlobStorageExportFrequency", + "BlobStorageExportMode", + "BlobStorageIntegrationDeletionResponse", + "BlobStorageIntegrationFileType", + "BlobStorageIntegrationResponse", + "BlobStorageIntegrationType", + "BlobStorageIntegrationsResponse", + "CreateBlobStorageIntegrationRequest", +] diff --git a/langfuse/api/blob_storage_integrations/client.py b/langfuse/api/blob_storage_integrations/client.py new file mode 100644 index 000000000..3833cca57 --- /dev/null +++ b/langfuse/api/blob_storage_integrations/client.py @@ -0,0 +1,451 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import ( + AsyncRawBlobStorageIntegrationsClient, + RawBlobStorageIntegrationsClient, +) +from .types.blob_storage_export_frequency import BlobStorageExportFrequency +from .types.blob_storage_export_mode import BlobStorageExportMode +from .types.blob_storage_integration_deletion_response import ( + BlobStorageIntegrationDeletionResponse, +) +from .types.blob_storage_integration_file_type import BlobStorageIntegrationFileType +from .types.blob_storage_integration_response import BlobStorageIntegrationResponse +from .types.blob_storage_integration_type import BlobStorageIntegrationType +from .types.blob_storage_integrations_response import BlobStorageIntegrationsResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class BlobStorageIntegrationsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawBlobStorageIntegrationsClient( + client_wrapper=client_wrapper + ) + + @property + def with_raw_response(self) -> RawBlobStorageIntegrationsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawBlobStorageIntegrationsClient + """ + return self._raw_client + + def get_blob_storage_integrations( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> BlobStorageIntegrationsResponse: + """ + Get all blob storage integrations for the organization (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + BlobStorageIntegrationsResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.blob_storage_integrations.get_blob_storage_integrations() + """ + _response = self._raw_client.get_blob_storage_integrations( + request_options=request_options + ) + return _response.data + + def upsert_blob_storage_integration( + self, + *, + project_id: str, + type: BlobStorageIntegrationType, + bucket_name: str, + region: str, + export_frequency: BlobStorageExportFrequency, + enabled: bool, + force_path_style: bool, + file_type: BlobStorageIntegrationFileType, + export_mode: BlobStorageExportMode, + endpoint: typing.Optional[str] = OMIT, + access_key_id: typing.Optional[str] = OMIT, + secret_access_key: typing.Optional[str] = OMIT, + prefix: typing.Optional[str] = OMIT, + export_start_date: typing.Optional[dt.datetime] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> BlobStorageIntegrationResponse: + """ + Create or update a blob storage integration for a specific project (requires organization-scoped API key). The configuration is validated by performing a test upload to the bucket. + + Parameters + ---------- + project_id : str + ID of the project in which to configure the blob storage integration + + type : BlobStorageIntegrationType + + bucket_name : str + Name of the storage bucket + + region : str + Storage region + + export_frequency : BlobStorageExportFrequency + + enabled : bool + Whether the integration is active + + force_path_style : bool + Use path-style URLs for S3 requests + + file_type : BlobStorageIntegrationFileType + + export_mode : BlobStorageExportMode + + endpoint : typing.Optional[str] + Custom endpoint URL (required for S3_COMPATIBLE type) + + access_key_id : typing.Optional[str] + Access key ID for authentication + + secret_access_key : typing.Optional[str] + Secret access key for authentication (will be encrypted when stored) + + prefix : typing.Optional[str] + Path prefix for exported files (must end with forward slash if provided) + + export_start_date : typing.Optional[dt.datetime] + Custom start date for exports (required when exportMode is FROM_CUSTOM_DATE) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + BlobStorageIntegrationResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.blob_storage_integrations.upsert_blob_storage_integration( + project_id="projectId", + type="S3", + bucket_name="bucketName", + region="region", + export_frequency="hourly", + enabled=True, + force_path_style=True, + file_type="JSON", + export_mode="FULL_HISTORY", + ) + """ + _response = self._raw_client.upsert_blob_storage_integration( + project_id=project_id, + type=type, + bucket_name=bucket_name, + region=region, + export_frequency=export_frequency, + enabled=enabled, + force_path_style=force_path_style, + file_type=file_type, + export_mode=export_mode, + endpoint=endpoint, + access_key_id=access_key_id, + secret_access_key=secret_access_key, + prefix=prefix, + export_start_date=export_start_date, + request_options=request_options, + ) + return _response.data + + def delete_blob_storage_integration( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> BlobStorageIntegrationDeletionResponse: + """ + Delete a blob storage integration by ID (requires organization-scoped API key) + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + BlobStorageIntegrationDeletionResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.blob_storage_integrations.delete_blob_storage_integration( + id="id", + ) + """ + _response = self._raw_client.delete_blob_storage_integration( + id, request_options=request_options + ) + return _response.data + + +class AsyncBlobStorageIntegrationsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawBlobStorageIntegrationsClient( + client_wrapper=client_wrapper + ) + + @property + def with_raw_response(self) -> AsyncRawBlobStorageIntegrationsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawBlobStorageIntegrationsClient + """ + return self._raw_client + + async def get_blob_storage_integrations( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> BlobStorageIntegrationsResponse: + """ + Get all blob storage integrations for the organization (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + BlobStorageIntegrationsResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.blob_storage_integrations.get_blob_storage_integrations() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_blob_storage_integrations( + request_options=request_options + ) + return _response.data + + async def upsert_blob_storage_integration( + self, + *, + project_id: str, + type: BlobStorageIntegrationType, + bucket_name: str, + region: str, + export_frequency: BlobStorageExportFrequency, + enabled: bool, + force_path_style: bool, + file_type: BlobStorageIntegrationFileType, + export_mode: BlobStorageExportMode, + endpoint: typing.Optional[str] = OMIT, + access_key_id: typing.Optional[str] = OMIT, + secret_access_key: typing.Optional[str] = OMIT, + prefix: typing.Optional[str] = OMIT, + export_start_date: typing.Optional[dt.datetime] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> BlobStorageIntegrationResponse: + """ + Create or update a blob storage integration for a specific project (requires organization-scoped API key). The configuration is validated by performing a test upload to the bucket. + + Parameters + ---------- + project_id : str + ID of the project in which to configure the blob storage integration + + type : BlobStorageIntegrationType + + bucket_name : str + Name of the storage bucket + + region : str + Storage region + + export_frequency : BlobStorageExportFrequency + + enabled : bool + Whether the integration is active + + force_path_style : bool + Use path-style URLs for S3 requests + + file_type : BlobStorageIntegrationFileType + + export_mode : BlobStorageExportMode + + endpoint : typing.Optional[str] + Custom endpoint URL (required for S3_COMPATIBLE type) + + access_key_id : typing.Optional[str] + Access key ID for authentication + + secret_access_key : typing.Optional[str] + Secret access key for authentication (will be encrypted when stored) + + prefix : typing.Optional[str] + Path prefix for exported files (must end with forward slash if provided) + + export_start_date : typing.Optional[dt.datetime] + Custom start date for exports (required when exportMode is FROM_CUSTOM_DATE) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + BlobStorageIntegrationResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.blob_storage_integrations.upsert_blob_storage_integration( + project_id="projectId", + type="S3", + bucket_name="bucketName", + region="region", + export_frequency="hourly", + enabled=True, + force_path_style=True, + file_type="JSON", + export_mode="FULL_HISTORY", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.upsert_blob_storage_integration( + project_id=project_id, + type=type, + bucket_name=bucket_name, + region=region, + export_frequency=export_frequency, + enabled=enabled, + force_path_style=force_path_style, + file_type=file_type, + export_mode=export_mode, + endpoint=endpoint, + access_key_id=access_key_id, + secret_access_key=secret_access_key, + prefix=prefix, + export_start_date=export_start_date, + request_options=request_options, + ) + return _response.data + + async def delete_blob_storage_integration( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> BlobStorageIntegrationDeletionResponse: + """ + Delete a blob storage integration by ID (requires organization-scoped API key) + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + BlobStorageIntegrationDeletionResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.blob_storage_integrations.delete_blob_storage_integration( + id="id", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete_blob_storage_integration( + id, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/blob_storage_integrations/raw_client.py b/langfuse/api/blob_storage_integrations/raw_client.py new file mode 100644 index 000000000..00ee72316 --- /dev/null +++ b/langfuse/api/blob_storage_integrations/raw_client.py @@ -0,0 +1,773 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.blob_storage_export_frequency import BlobStorageExportFrequency +from .types.blob_storage_export_mode import BlobStorageExportMode +from .types.blob_storage_integration_deletion_response import ( + BlobStorageIntegrationDeletionResponse, +) +from .types.blob_storage_integration_file_type import BlobStorageIntegrationFileType +from .types.blob_storage_integration_response import BlobStorageIntegrationResponse +from .types.blob_storage_integration_type import BlobStorageIntegrationType +from .types.blob_storage_integrations_response import BlobStorageIntegrationsResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawBlobStorageIntegrationsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get_blob_storage_integrations( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[BlobStorageIntegrationsResponse]: + """ + Get all blob storage integrations for the organization (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[BlobStorageIntegrationsResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/integrations/blob-storage", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + BlobStorageIntegrationsResponse, + parse_obj_as( + type_=BlobStorageIntegrationsResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def upsert_blob_storage_integration( + self, + *, + project_id: str, + type: BlobStorageIntegrationType, + bucket_name: str, + region: str, + export_frequency: BlobStorageExportFrequency, + enabled: bool, + force_path_style: bool, + file_type: BlobStorageIntegrationFileType, + export_mode: BlobStorageExportMode, + endpoint: typing.Optional[str] = OMIT, + access_key_id: typing.Optional[str] = OMIT, + secret_access_key: typing.Optional[str] = OMIT, + prefix: typing.Optional[str] = OMIT, + export_start_date: typing.Optional[dt.datetime] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[BlobStorageIntegrationResponse]: + """ + Create or update a blob storage integration for a specific project (requires organization-scoped API key). The configuration is validated by performing a test upload to the bucket. + + Parameters + ---------- + project_id : str + ID of the project in which to configure the blob storage integration + + type : BlobStorageIntegrationType + + bucket_name : str + Name of the storage bucket + + region : str + Storage region + + export_frequency : BlobStorageExportFrequency + + enabled : bool + Whether the integration is active + + force_path_style : bool + Use path-style URLs for S3 requests + + file_type : BlobStorageIntegrationFileType + + export_mode : BlobStorageExportMode + + endpoint : typing.Optional[str] + Custom endpoint URL (required for S3_COMPATIBLE type) + + access_key_id : typing.Optional[str] + Access key ID for authentication + + secret_access_key : typing.Optional[str] + Secret access key for authentication (will be encrypted when stored) + + prefix : typing.Optional[str] + Path prefix for exported files (must end with forward slash if provided) + + export_start_date : typing.Optional[dt.datetime] + Custom start date for exports (required when exportMode is FROM_CUSTOM_DATE) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[BlobStorageIntegrationResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/integrations/blob-storage", + method="PUT", + json={ + "projectId": project_id, + "type": type, + "bucketName": bucket_name, + "endpoint": endpoint, + "region": region, + "accessKeyId": access_key_id, + "secretAccessKey": secret_access_key, + "prefix": prefix, + "exportFrequency": export_frequency, + "enabled": enabled, + "forcePathStyle": force_path_style, + "fileType": file_type, + "exportMode": export_mode, + "exportStartDate": export_start_date, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + BlobStorageIntegrationResponse, + parse_obj_as( + type_=BlobStorageIntegrationResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete_blob_storage_integration( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[BlobStorageIntegrationDeletionResponse]: + """ + Delete a blob storage integration by ID (requires organization-scoped API key) + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[BlobStorageIntegrationDeletionResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/integrations/blob-storage/{jsonable_encoder(id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + BlobStorageIntegrationDeletionResponse, + parse_obj_as( + type_=BlobStorageIntegrationDeletionResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawBlobStorageIntegrationsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get_blob_storage_integrations( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[BlobStorageIntegrationsResponse]: + """ + Get all blob storage integrations for the organization (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[BlobStorageIntegrationsResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/integrations/blob-storage", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + BlobStorageIntegrationsResponse, + parse_obj_as( + type_=BlobStorageIntegrationsResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def upsert_blob_storage_integration( + self, + *, + project_id: str, + type: BlobStorageIntegrationType, + bucket_name: str, + region: str, + export_frequency: BlobStorageExportFrequency, + enabled: bool, + force_path_style: bool, + file_type: BlobStorageIntegrationFileType, + export_mode: BlobStorageExportMode, + endpoint: typing.Optional[str] = OMIT, + access_key_id: typing.Optional[str] = OMIT, + secret_access_key: typing.Optional[str] = OMIT, + prefix: typing.Optional[str] = OMIT, + export_start_date: typing.Optional[dt.datetime] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[BlobStorageIntegrationResponse]: + """ + Create or update a blob storage integration for a specific project (requires organization-scoped API key). The configuration is validated by performing a test upload to the bucket. + + Parameters + ---------- + project_id : str + ID of the project in which to configure the blob storage integration + + type : BlobStorageIntegrationType + + bucket_name : str + Name of the storage bucket + + region : str + Storage region + + export_frequency : BlobStorageExportFrequency + + enabled : bool + Whether the integration is active + + force_path_style : bool + Use path-style URLs for S3 requests + + file_type : BlobStorageIntegrationFileType + + export_mode : BlobStorageExportMode + + endpoint : typing.Optional[str] + Custom endpoint URL (required for S3_COMPATIBLE type) + + access_key_id : typing.Optional[str] + Access key ID for authentication + + secret_access_key : typing.Optional[str] + Secret access key for authentication (will be encrypted when stored) + + prefix : typing.Optional[str] + Path prefix for exported files (must end with forward slash if provided) + + export_start_date : typing.Optional[dt.datetime] + Custom start date for exports (required when exportMode is FROM_CUSTOM_DATE) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[BlobStorageIntegrationResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/integrations/blob-storage", + method="PUT", + json={ + "projectId": project_id, + "type": type, + "bucketName": bucket_name, + "endpoint": endpoint, + "region": region, + "accessKeyId": access_key_id, + "secretAccessKey": secret_access_key, + "prefix": prefix, + "exportFrequency": export_frequency, + "enabled": enabled, + "forcePathStyle": force_path_style, + "fileType": file_type, + "exportMode": export_mode, + "exportStartDate": export_start_date, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + BlobStorageIntegrationResponse, + parse_obj_as( + type_=BlobStorageIntegrationResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete_blob_storage_integration( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[BlobStorageIntegrationDeletionResponse]: + """ + Delete a blob storage integration by ID (requires organization-scoped API key) + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[BlobStorageIntegrationDeletionResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/integrations/blob-storage/{jsonable_encoder(id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + BlobStorageIntegrationDeletionResponse, + parse_obj_as( + type_=BlobStorageIntegrationDeletionResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/blob_storage_integrations/types/__init__.py b/langfuse/api/blob_storage_integrations/types/__init__.py new file mode 100644 index 000000000..cc19f1a6d --- /dev/null +++ b/langfuse/api/blob_storage_integrations/types/__init__.py @@ -0,0 +1,69 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .blob_storage_export_frequency import BlobStorageExportFrequency + from .blob_storage_export_mode import BlobStorageExportMode + from .blob_storage_integration_deletion_response import ( + BlobStorageIntegrationDeletionResponse, + ) + from .blob_storage_integration_file_type import BlobStorageIntegrationFileType + from .blob_storage_integration_response import BlobStorageIntegrationResponse + from .blob_storage_integration_type import BlobStorageIntegrationType + from .blob_storage_integrations_response import BlobStorageIntegrationsResponse + from .create_blob_storage_integration_request import ( + CreateBlobStorageIntegrationRequest, + ) +_dynamic_imports: typing.Dict[str, str] = { + "BlobStorageExportFrequency": ".blob_storage_export_frequency", + "BlobStorageExportMode": ".blob_storage_export_mode", + "BlobStorageIntegrationDeletionResponse": ".blob_storage_integration_deletion_response", + "BlobStorageIntegrationFileType": ".blob_storage_integration_file_type", + "BlobStorageIntegrationResponse": ".blob_storage_integration_response", + "BlobStorageIntegrationType": ".blob_storage_integration_type", + "BlobStorageIntegrationsResponse": ".blob_storage_integrations_response", + "CreateBlobStorageIntegrationRequest": ".create_blob_storage_integration_request", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "BlobStorageExportFrequency", + "BlobStorageExportMode", + "BlobStorageIntegrationDeletionResponse", + "BlobStorageIntegrationFileType", + "BlobStorageIntegrationResponse", + "BlobStorageIntegrationType", + "BlobStorageIntegrationsResponse", + "CreateBlobStorageIntegrationRequest", +] diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_export_frequency.py b/langfuse/api/blob_storage_integrations/types/blob_storage_export_frequency.py new file mode 100644 index 000000000..a7307c30e --- /dev/null +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_export_frequency.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +BlobStorageExportFrequency = typing.Union[ + typing.Literal["hourly", "daily", "weekly"], typing.Any +] diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_export_mode.py b/langfuse/api/blob_storage_integrations/types/blob_storage_export_mode.py new file mode 100644 index 000000000..f1b1d95a3 --- /dev/null +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_export_mode.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +BlobStorageExportMode = typing.Union[ + typing.Literal["FULL_HISTORY", "FROM_TODAY", "FROM_CUSTOM_DATE"], typing.Any +] diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py new file mode 100644 index 000000000..aaeac99e2 --- /dev/null +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class BlobStorageIntegrationDeletionResponse(UniversalBaseModel): + message: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_file_type.py b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_file_type.py new file mode 100644 index 000000000..09e8762ab --- /dev/null +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_file_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +BlobStorageIntegrationFileType = typing.Union[ + typing.Literal["JSON", "CSV", "JSONL"], typing.Any +] diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py new file mode 100644 index 000000000..0e5821d32 --- /dev/null +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py @@ -0,0 +1,65 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .blob_storage_export_frequency import BlobStorageExportFrequency +from .blob_storage_export_mode import BlobStorageExportMode +from .blob_storage_integration_file_type import BlobStorageIntegrationFileType +from .blob_storage_integration_type import BlobStorageIntegrationType + + +class BlobStorageIntegrationResponse(UniversalBaseModel): + id: str + project_id: typing_extensions.Annotated[str, FieldMetadata(alias="projectId")] + type: BlobStorageIntegrationType + bucket_name: typing_extensions.Annotated[str, FieldMetadata(alias="bucketName")] + endpoint: typing.Optional[str] = None + region: str + access_key_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="accessKeyId") + ] = None + prefix: str + export_frequency: typing_extensions.Annotated[ + BlobStorageExportFrequency, FieldMetadata(alias="exportFrequency") + ] + enabled: bool + force_path_style: typing_extensions.Annotated[ + bool, FieldMetadata(alias="forcePathStyle") + ] + file_type: typing_extensions.Annotated[ + BlobStorageIntegrationFileType, FieldMetadata(alias="fileType") + ] + export_mode: typing_extensions.Annotated[ + BlobStorageExportMode, FieldMetadata(alias="exportMode") + ] + export_start_date: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="exportStartDate") + ] = None + next_sync_at: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="nextSyncAt") + ] = None + last_sync_at: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="lastSyncAt") + ] = None + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_type.py b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_type.py new file mode 100644 index 000000000..0df026d37 --- /dev/null +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +BlobStorageIntegrationType = typing.Union[ + typing.Literal["S3", "S3_COMPATIBLE", "AZURE_BLOB_STORAGE"], typing.Any +] diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_integrations_response.py b/langfuse/api/blob_storage_integrations/types/blob_storage_integrations_response.py new file mode 100644 index 000000000..ffa5760a9 --- /dev/null +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_integrations_response.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .blob_storage_integration_response import BlobStorageIntegrationResponse + + +class BlobStorageIntegrationsResponse(UniversalBaseModel): + data: typing.List[BlobStorageIntegrationResponse] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py b/langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py new file mode 100644 index 000000000..69b56bda0 --- /dev/null +++ b/langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py @@ -0,0 +1,98 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .blob_storage_export_frequency import BlobStorageExportFrequency +from .blob_storage_export_mode import BlobStorageExportMode +from .blob_storage_integration_file_type import BlobStorageIntegrationFileType +from .blob_storage_integration_type import BlobStorageIntegrationType + + +class CreateBlobStorageIntegrationRequest(UniversalBaseModel): + project_id: typing_extensions.Annotated[str, FieldMetadata(alias="projectId")] = ( + pydantic.Field() + ) + """ + ID of the project in which to configure the blob storage integration + """ + + type: BlobStorageIntegrationType + bucket_name: typing_extensions.Annotated[str, FieldMetadata(alias="bucketName")] = ( + pydantic.Field() + ) + """ + Name of the storage bucket + """ + + endpoint: typing.Optional[str] = pydantic.Field(default=None) + """ + Custom endpoint URL (required for S3_COMPATIBLE type) + """ + + region: str = pydantic.Field() + """ + Storage region + """ + + access_key_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="accessKeyId") + ] = pydantic.Field(default=None) + """ + Access key ID for authentication + """ + + secret_access_key: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="secretAccessKey") + ] = pydantic.Field(default=None) + """ + Secret access key for authentication (will be encrypted when stored) + """ + + prefix: typing.Optional[str] = pydantic.Field(default=None) + """ + Path prefix for exported files (must end with forward slash if provided) + """ + + export_frequency: typing_extensions.Annotated[ + BlobStorageExportFrequency, FieldMetadata(alias="exportFrequency") + ] + enabled: bool = pydantic.Field() + """ + Whether the integration is active + """ + + force_path_style: typing_extensions.Annotated[ + bool, FieldMetadata(alias="forcePathStyle") + ] = pydantic.Field() + """ + Use path-style URLs for S3 requests + """ + + file_type: typing_extensions.Annotated[ + BlobStorageIntegrationFileType, FieldMetadata(alias="fileType") + ] + export_mode: typing_extensions.Annotated[ + BlobStorageExportMode, FieldMetadata(alias="exportMode") + ] + export_start_date: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="exportStartDate") + ] = pydantic.Field(default=None) + """ + Custom start date for exports (required when exportMode is FROM_CUSTOM_DATE) + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/client.py b/langfuse/api/client.py index 646279b5a..14c1ae54f 100644 --- a/langfuse/api/client.py +++ b/langfuse/api/client.py @@ -1,58 +1,49 @@ # This file was auto-generated by Fern from our API Definition. +from __future__ import annotations + import typing import httpx - from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from .resources.annotation_queues.client import ( - AnnotationQueuesClient, - AsyncAnnotationQueuesClient, -) -from .resources.blob_storage_integrations.client import ( - AsyncBlobStorageIntegrationsClient, - BlobStorageIntegrationsClient, -) -from .resources.comments.client import AsyncCommentsClient, CommentsClient -from .resources.dataset_items.client import AsyncDatasetItemsClient, DatasetItemsClient -from .resources.dataset_run_items.client import ( - AsyncDatasetRunItemsClient, - DatasetRunItemsClient, -) -from .resources.datasets.client import AsyncDatasetsClient, DatasetsClient -from .resources.health.client import AsyncHealthClient, HealthClient -from .resources.ingestion.client import AsyncIngestionClient, IngestionClient -from .resources.llm_connections.client import ( - AsyncLlmConnectionsClient, - LlmConnectionsClient, -) -from .resources.media.client import AsyncMediaClient, MediaClient -from .resources.metrics.client import AsyncMetricsClient, MetricsClient -from .resources.models.client import AsyncModelsClient, ModelsClient -from .resources.observations.client import AsyncObservationsClient, ObservationsClient -from .resources.opentelemetry.client import ( - AsyncOpentelemetryClient, - OpentelemetryClient, -) -from .resources.organizations.client import ( - AsyncOrganizationsClient, - OrganizationsClient, -) -from .resources.projects.client import AsyncProjectsClient, ProjectsClient -from .resources.prompt_version.client import ( - AsyncPromptVersionClient, - PromptVersionClient, -) -from .resources.prompts.client import AsyncPromptsClient, PromptsClient -from .resources.scim.client import AsyncScimClient, ScimClient -from .resources.score.client import AsyncScoreClient, ScoreClient -from .resources.score_configs.client import AsyncScoreConfigsClient, ScoreConfigsClient -from .resources.score_v_2.client import AsyncScoreV2Client, ScoreV2Client -from .resources.sessions.client import AsyncSessionsClient, SessionsClient -from .resources.trace.client import AsyncTraceClient, TraceClient - - -class FernLangfuse: + +if typing.TYPE_CHECKING: + from .annotation_queues.client import ( + AnnotationQueuesClient, + AsyncAnnotationQueuesClient, + ) + from .blob_storage_integrations.client import ( + AsyncBlobStorageIntegrationsClient, + BlobStorageIntegrationsClient, + ) + from .comments.client import AsyncCommentsClient, CommentsClient + from .dataset_items.client import AsyncDatasetItemsClient, DatasetItemsClient + from .dataset_run_items.client import ( + AsyncDatasetRunItemsClient, + DatasetRunItemsClient, + ) + from .datasets.client import AsyncDatasetsClient, DatasetsClient + from .health.client import AsyncHealthClient, HealthClient + from .ingestion.client import AsyncIngestionClient, IngestionClient + from .llm_connections.client import AsyncLlmConnectionsClient, LlmConnectionsClient + from .media.client import AsyncMediaClient, MediaClient + from .metrics.client import AsyncMetricsClient, MetricsClient + from .models.client import AsyncModelsClient, ModelsClient + from .observations.client import AsyncObservationsClient, ObservationsClient + from .opentelemetry.client import AsyncOpentelemetryClient, OpentelemetryClient + from .organizations.client import AsyncOrganizationsClient, OrganizationsClient + from .projects.client import AsyncProjectsClient, ProjectsClient + from .prompt_version.client import AsyncPromptVersionClient, PromptVersionClient + from .prompts.client import AsyncPromptsClient, PromptsClient + from .scim.client import AsyncScimClient, ScimClient + from .score.client import AsyncScoreClient, ScoreClient + from .score_configs.client import AsyncScoreConfigsClient, ScoreConfigsClient + from .score_v2.client import AsyncScoreV2Client, ScoreV2Client + from .sessions.client import AsyncSessionsClient, SessionsClient + from .trace.client import AsyncTraceClient, TraceClient + + +class LangfuseAPI: """ Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions. @@ -66,6 +57,9 @@ class FernLangfuse: x_langfuse_public_key : typing.Optional[str] username : typing.Optional[typing.Union[str, typing.Callable[[], str]]] password : typing.Optional[typing.Union[str, typing.Callable[[], str]]] + headers : typing.Optional[typing.Dict[str, str]] + Additional headers to send with every request. + timeout : typing.Optional[float] The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced. @@ -77,9 +71,9 @@ class FernLangfuse: Examples -------- - from langfuse.client import FernLangfuse + from langfuse import LangfuseAPI - client = FernLangfuse( + client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -98,12 +92,17 @@ def __init__( x_langfuse_public_key: typing.Optional[str] = None, username: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, password: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, httpx_client: typing.Optional[httpx.Client] = None, ): _defaulted_timeout = ( - timeout if timeout is not None else 60 if httpx_client is None else None + timeout + if timeout is not None + else 60 + if httpx_client is None + else httpx_client.timeout.read ) self._client_wrapper = SyncClientWrapper( base_url=base_url, @@ -112,6 +111,7 @@ def __init__( x_langfuse_public_key=x_langfuse_public_key, username=username, password=password, + headers=headers, httpx_client=httpx_client if httpx_client is not None else httpx.Client( @@ -121,39 +121,245 @@ def __init__( else httpx.Client(timeout=_defaulted_timeout), timeout=_defaulted_timeout, ) - self.annotation_queues = AnnotationQueuesClient( - client_wrapper=self._client_wrapper - ) - self.blob_storage_integrations = BlobStorageIntegrationsClient( - client_wrapper=self._client_wrapper - ) - self.comments = CommentsClient(client_wrapper=self._client_wrapper) - self.dataset_items = DatasetItemsClient(client_wrapper=self._client_wrapper) - self.dataset_run_items = DatasetRunItemsClient( - client_wrapper=self._client_wrapper - ) - self.datasets = DatasetsClient(client_wrapper=self._client_wrapper) - self.health = HealthClient(client_wrapper=self._client_wrapper) - self.ingestion = IngestionClient(client_wrapper=self._client_wrapper) - self.llm_connections = LlmConnectionsClient(client_wrapper=self._client_wrapper) - self.media = MediaClient(client_wrapper=self._client_wrapper) - self.metrics = MetricsClient(client_wrapper=self._client_wrapper) - self.models = ModelsClient(client_wrapper=self._client_wrapper) - self.observations = ObservationsClient(client_wrapper=self._client_wrapper) - self.opentelemetry = OpentelemetryClient(client_wrapper=self._client_wrapper) - self.organizations = OrganizationsClient(client_wrapper=self._client_wrapper) - self.projects = ProjectsClient(client_wrapper=self._client_wrapper) - self.prompt_version = PromptVersionClient(client_wrapper=self._client_wrapper) - self.prompts = PromptsClient(client_wrapper=self._client_wrapper) - self.scim = ScimClient(client_wrapper=self._client_wrapper) - self.score_configs = ScoreConfigsClient(client_wrapper=self._client_wrapper) - self.score_v_2 = ScoreV2Client(client_wrapper=self._client_wrapper) - self.score = ScoreClient(client_wrapper=self._client_wrapper) - self.sessions = SessionsClient(client_wrapper=self._client_wrapper) - self.trace = TraceClient(client_wrapper=self._client_wrapper) - - -class AsyncFernLangfuse: + self._annotation_queues: typing.Optional[AnnotationQueuesClient] = None + self._blob_storage_integrations: typing.Optional[ + BlobStorageIntegrationsClient + ] = None + self._comments: typing.Optional[CommentsClient] = None + self._dataset_items: typing.Optional[DatasetItemsClient] = None + self._dataset_run_items: typing.Optional[DatasetRunItemsClient] = None + self._datasets: typing.Optional[DatasetsClient] = None + self._health: typing.Optional[HealthClient] = None + self._ingestion: typing.Optional[IngestionClient] = None + self._llm_connections: typing.Optional[LlmConnectionsClient] = None + self._media: typing.Optional[MediaClient] = None + self._metrics: typing.Optional[MetricsClient] = None + self._models: typing.Optional[ModelsClient] = None + self._observations: typing.Optional[ObservationsClient] = None + self._opentelemetry: typing.Optional[OpentelemetryClient] = None + self._organizations: typing.Optional[OrganizationsClient] = None + self._projects: typing.Optional[ProjectsClient] = None + self._prompt_version: typing.Optional[PromptVersionClient] = None + self._prompts: typing.Optional[PromptsClient] = None + self._scim: typing.Optional[ScimClient] = None + self._score_configs: typing.Optional[ScoreConfigsClient] = None + self._score_v2: typing.Optional[ScoreV2Client] = None + self._score: typing.Optional[ScoreClient] = None + self._sessions: typing.Optional[SessionsClient] = None + self._trace: typing.Optional[TraceClient] = None + + @property + def annotation_queues(self): + if self._annotation_queues is None: + from .annotation_queues.client import AnnotationQueuesClient # noqa: E402 + + self._annotation_queues = AnnotationQueuesClient( + client_wrapper=self._client_wrapper + ) + return self._annotation_queues + + @property + def blob_storage_integrations(self): + if self._blob_storage_integrations is None: + from .blob_storage_integrations.client import BlobStorageIntegrationsClient # noqa: E402 + + self._blob_storage_integrations = BlobStorageIntegrationsClient( + client_wrapper=self._client_wrapper + ) + return self._blob_storage_integrations + + @property + def comments(self): + if self._comments is None: + from .comments.client import CommentsClient # noqa: E402 + + self._comments = CommentsClient(client_wrapper=self._client_wrapper) + return self._comments + + @property + def dataset_items(self): + if self._dataset_items is None: + from .dataset_items.client import DatasetItemsClient # noqa: E402 + + self._dataset_items = DatasetItemsClient( + client_wrapper=self._client_wrapper + ) + return self._dataset_items + + @property + def dataset_run_items(self): + if self._dataset_run_items is None: + from .dataset_run_items.client import DatasetRunItemsClient # noqa: E402 + + self._dataset_run_items = DatasetRunItemsClient( + client_wrapper=self._client_wrapper + ) + return self._dataset_run_items + + @property + def datasets(self): + if self._datasets is None: + from .datasets.client import DatasetsClient # noqa: E402 + + self._datasets = DatasetsClient(client_wrapper=self._client_wrapper) + return self._datasets + + @property + def health(self): + if self._health is None: + from .health.client import HealthClient # noqa: E402 + + self._health = HealthClient(client_wrapper=self._client_wrapper) + return self._health + + @property + def ingestion(self): + if self._ingestion is None: + from .ingestion.client import IngestionClient # noqa: E402 + + self._ingestion = IngestionClient(client_wrapper=self._client_wrapper) + return self._ingestion + + @property + def llm_connections(self): + if self._llm_connections is None: + from .llm_connections.client import LlmConnectionsClient # noqa: E402 + + self._llm_connections = LlmConnectionsClient( + client_wrapper=self._client_wrapper + ) + return self._llm_connections + + @property + def media(self): + if self._media is None: + from .media.client import MediaClient # noqa: E402 + + self._media = MediaClient(client_wrapper=self._client_wrapper) + return self._media + + @property + def metrics(self): + if self._metrics is None: + from .metrics.client import MetricsClient # noqa: E402 + + self._metrics = MetricsClient(client_wrapper=self._client_wrapper) + return self._metrics + + @property + def models(self): + if self._models is None: + from .models.client import ModelsClient # noqa: E402 + + self._models = ModelsClient(client_wrapper=self._client_wrapper) + return self._models + + @property + def observations(self): + if self._observations is None: + from .observations.client import ObservationsClient # noqa: E402 + + self._observations = ObservationsClient(client_wrapper=self._client_wrapper) + return self._observations + + @property + def opentelemetry(self): + if self._opentelemetry is None: + from .opentelemetry.client import OpentelemetryClient # noqa: E402 + + self._opentelemetry = OpentelemetryClient( + client_wrapper=self._client_wrapper + ) + return self._opentelemetry + + @property + def organizations(self): + if self._organizations is None: + from .organizations.client import OrganizationsClient # noqa: E402 + + self._organizations = OrganizationsClient( + client_wrapper=self._client_wrapper + ) + return self._organizations + + @property + def projects(self): + if self._projects is None: + from .projects.client import ProjectsClient # noqa: E402 + + self._projects = ProjectsClient(client_wrapper=self._client_wrapper) + return self._projects + + @property + def prompt_version(self): + if self._prompt_version is None: + from .prompt_version.client import PromptVersionClient # noqa: E402 + + self._prompt_version = PromptVersionClient( + client_wrapper=self._client_wrapper + ) + return self._prompt_version + + @property + def prompts(self): + if self._prompts is None: + from .prompts.client import PromptsClient # noqa: E402 + + self._prompts = PromptsClient(client_wrapper=self._client_wrapper) + return self._prompts + + @property + def scim(self): + if self._scim is None: + from .scim.client import ScimClient # noqa: E402 + + self._scim = ScimClient(client_wrapper=self._client_wrapper) + return self._scim + + @property + def score_configs(self): + if self._score_configs is None: + from .score_configs.client import ScoreConfigsClient # noqa: E402 + + self._score_configs = ScoreConfigsClient( + client_wrapper=self._client_wrapper + ) + return self._score_configs + + @property + def score_v2(self): + if self._score_v2 is None: + from .score_v2.client import ScoreV2Client # noqa: E402 + + self._score_v2 = ScoreV2Client(client_wrapper=self._client_wrapper) + return self._score_v2 + + @property + def score(self): + if self._score is None: + from .score.client import ScoreClient # noqa: E402 + + self._score = ScoreClient(client_wrapper=self._client_wrapper) + return self._score + + @property + def sessions(self): + if self._sessions is None: + from .sessions.client import SessionsClient # noqa: E402 + + self._sessions = SessionsClient(client_wrapper=self._client_wrapper) + return self._sessions + + @property + def trace(self): + if self._trace is None: + from .trace.client import TraceClient # noqa: E402 + + self._trace = TraceClient(client_wrapper=self._client_wrapper) + return self._trace + + +class AsyncLangfuseAPI: """ Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions. @@ -167,6 +373,9 @@ class AsyncFernLangfuse: x_langfuse_public_key : typing.Optional[str] username : typing.Optional[typing.Union[str, typing.Callable[[], str]]] password : typing.Optional[typing.Union[str, typing.Callable[[], str]]] + headers : typing.Optional[typing.Dict[str, str]] + Additional headers to send with every request. + timeout : typing.Optional[float] The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced. @@ -178,9 +387,9 @@ class AsyncFernLangfuse: Examples -------- - from langfuse.client import AsyncFernLangfuse + from langfuse import AsyncLangfuseAPI - client = AsyncFernLangfuse( + client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -199,12 +408,17 @@ def __init__( x_langfuse_public_key: typing.Optional[str] = None, username: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, password: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, timeout: typing.Optional[float] = None, follow_redirects: typing.Optional[bool] = True, httpx_client: typing.Optional[httpx.AsyncClient] = None, ): _defaulted_timeout = ( - timeout if timeout is not None else 60 if httpx_client is None else None + timeout + if timeout is not None + else 60 + if httpx_client is None + else httpx_client.timeout.read ) self._client_wrapper = AsyncClientWrapper( base_url=base_url, @@ -213,6 +427,7 @@ def __init__( x_langfuse_public_key=x_langfuse_public_key, username=username, password=password, + headers=headers, httpx_client=httpx_client if httpx_client is not None else httpx.AsyncClient( @@ -222,45 +437,243 @@ def __init__( else httpx.AsyncClient(timeout=_defaulted_timeout), timeout=_defaulted_timeout, ) - self.annotation_queues = AsyncAnnotationQueuesClient( - client_wrapper=self._client_wrapper - ) - self.blob_storage_integrations = AsyncBlobStorageIntegrationsClient( - client_wrapper=self._client_wrapper - ) - self.comments = AsyncCommentsClient(client_wrapper=self._client_wrapper) - self.dataset_items = AsyncDatasetItemsClient( - client_wrapper=self._client_wrapper - ) - self.dataset_run_items = AsyncDatasetRunItemsClient( - client_wrapper=self._client_wrapper - ) - self.datasets = AsyncDatasetsClient(client_wrapper=self._client_wrapper) - self.health = AsyncHealthClient(client_wrapper=self._client_wrapper) - self.ingestion = AsyncIngestionClient(client_wrapper=self._client_wrapper) - self.llm_connections = AsyncLlmConnectionsClient( - client_wrapper=self._client_wrapper - ) - self.media = AsyncMediaClient(client_wrapper=self._client_wrapper) - self.metrics = AsyncMetricsClient(client_wrapper=self._client_wrapper) - self.models = AsyncModelsClient(client_wrapper=self._client_wrapper) - self.observations = AsyncObservationsClient(client_wrapper=self._client_wrapper) - self.opentelemetry = AsyncOpentelemetryClient( - client_wrapper=self._client_wrapper - ) - self.organizations = AsyncOrganizationsClient( - client_wrapper=self._client_wrapper - ) - self.projects = AsyncProjectsClient(client_wrapper=self._client_wrapper) - self.prompt_version = AsyncPromptVersionClient( - client_wrapper=self._client_wrapper - ) - self.prompts = AsyncPromptsClient(client_wrapper=self._client_wrapper) - self.scim = AsyncScimClient(client_wrapper=self._client_wrapper) - self.score_configs = AsyncScoreConfigsClient( - client_wrapper=self._client_wrapper - ) - self.score_v_2 = AsyncScoreV2Client(client_wrapper=self._client_wrapper) - self.score = AsyncScoreClient(client_wrapper=self._client_wrapper) - self.sessions = AsyncSessionsClient(client_wrapper=self._client_wrapper) - self.trace = AsyncTraceClient(client_wrapper=self._client_wrapper) + self._annotation_queues: typing.Optional[AsyncAnnotationQueuesClient] = None + self._blob_storage_integrations: typing.Optional[ + AsyncBlobStorageIntegrationsClient + ] = None + self._comments: typing.Optional[AsyncCommentsClient] = None + self._dataset_items: typing.Optional[AsyncDatasetItemsClient] = None + self._dataset_run_items: typing.Optional[AsyncDatasetRunItemsClient] = None + self._datasets: typing.Optional[AsyncDatasetsClient] = None + self._health: typing.Optional[AsyncHealthClient] = None + self._ingestion: typing.Optional[AsyncIngestionClient] = None + self._llm_connections: typing.Optional[AsyncLlmConnectionsClient] = None + self._media: typing.Optional[AsyncMediaClient] = None + self._metrics: typing.Optional[AsyncMetricsClient] = None + self._models: typing.Optional[AsyncModelsClient] = None + self._observations: typing.Optional[AsyncObservationsClient] = None + self._opentelemetry: typing.Optional[AsyncOpentelemetryClient] = None + self._organizations: typing.Optional[AsyncOrganizationsClient] = None + self._projects: typing.Optional[AsyncProjectsClient] = None + self._prompt_version: typing.Optional[AsyncPromptVersionClient] = None + self._prompts: typing.Optional[AsyncPromptsClient] = None + self._scim: typing.Optional[AsyncScimClient] = None + self._score_configs: typing.Optional[AsyncScoreConfigsClient] = None + self._score_v2: typing.Optional[AsyncScoreV2Client] = None + self._score: typing.Optional[AsyncScoreClient] = None + self._sessions: typing.Optional[AsyncSessionsClient] = None + self._trace: typing.Optional[AsyncTraceClient] = None + + @property + def annotation_queues(self): + if self._annotation_queues is None: + from .annotation_queues.client import AsyncAnnotationQueuesClient # noqa: E402 + + self._annotation_queues = AsyncAnnotationQueuesClient( + client_wrapper=self._client_wrapper + ) + return self._annotation_queues + + @property + def blob_storage_integrations(self): + if self._blob_storage_integrations is None: + from .blob_storage_integrations.client import ( + AsyncBlobStorageIntegrationsClient, + ) # noqa: E402 + + self._blob_storage_integrations = AsyncBlobStorageIntegrationsClient( + client_wrapper=self._client_wrapper + ) + return self._blob_storage_integrations + + @property + def comments(self): + if self._comments is None: + from .comments.client import AsyncCommentsClient # noqa: E402 + + self._comments = AsyncCommentsClient(client_wrapper=self._client_wrapper) + return self._comments + + @property + def dataset_items(self): + if self._dataset_items is None: + from .dataset_items.client import AsyncDatasetItemsClient # noqa: E402 + + self._dataset_items = AsyncDatasetItemsClient( + client_wrapper=self._client_wrapper + ) + return self._dataset_items + + @property + def dataset_run_items(self): + if self._dataset_run_items is None: + from .dataset_run_items.client import AsyncDatasetRunItemsClient # noqa: E402 + + self._dataset_run_items = AsyncDatasetRunItemsClient( + client_wrapper=self._client_wrapper + ) + return self._dataset_run_items + + @property + def datasets(self): + if self._datasets is None: + from .datasets.client import AsyncDatasetsClient # noqa: E402 + + self._datasets = AsyncDatasetsClient(client_wrapper=self._client_wrapper) + return self._datasets + + @property + def health(self): + if self._health is None: + from .health.client import AsyncHealthClient # noqa: E402 + + self._health = AsyncHealthClient(client_wrapper=self._client_wrapper) + return self._health + + @property + def ingestion(self): + if self._ingestion is None: + from .ingestion.client import AsyncIngestionClient # noqa: E402 + + self._ingestion = AsyncIngestionClient(client_wrapper=self._client_wrapper) + return self._ingestion + + @property + def llm_connections(self): + if self._llm_connections is None: + from .llm_connections.client import AsyncLlmConnectionsClient # noqa: E402 + + self._llm_connections = AsyncLlmConnectionsClient( + client_wrapper=self._client_wrapper + ) + return self._llm_connections + + @property + def media(self): + if self._media is None: + from .media.client import AsyncMediaClient # noqa: E402 + + self._media = AsyncMediaClient(client_wrapper=self._client_wrapper) + return self._media + + @property + def metrics(self): + if self._metrics is None: + from .metrics.client import AsyncMetricsClient # noqa: E402 + + self._metrics = AsyncMetricsClient(client_wrapper=self._client_wrapper) + return self._metrics + + @property + def models(self): + if self._models is None: + from .models.client import AsyncModelsClient # noqa: E402 + + self._models = AsyncModelsClient(client_wrapper=self._client_wrapper) + return self._models + + @property + def observations(self): + if self._observations is None: + from .observations.client import AsyncObservationsClient # noqa: E402 + + self._observations = AsyncObservationsClient( + client_wrapper=self._client_wrapper + ) + return self._observations + + @property + def opentelemetry(self): + if self._opentelemetry is None: + from .opentelemetry.client import AsyncOpentelemetryClient # noqa: E402 + + self._opentelemetry = AsyncOpentelemetryClient( + client_wrapper=self._client_wrapper + ) + return self._opentelemetry + + @property + def organizations(self): + if self._organizations is None: + from .organizations.client import AsyncOrganizationsClient # noqa: E402 + + self._organizations = AsyncOrganizationsClient( + client_wrapper=self._client_wrapper + ) + return self._organizations + + @property + def projects(self): + if self._projects is None: + from .projects.client import AsyncProjectsClient # noqa: E402 + + self._projects = AsyncProjectsClient(client_wrapper=self._client_wrapper) + return self._projects + + @property + def prompt_version(self): + if self._prompt_version is None: + from .prompt_version.client import AsyncPromptVersionClient # noqa: E402 + + self._prompt_version = AsyncPromptVersionClient( + client_wrapper=self._client_wrapper + ) + return self._prompt_version + + @property + def prompts(self): + if self._prompts is None: + from .prompts.client import AsyncPromptsClient # noqa: E402 + + self._prompts = AsyncPromptsClient(client_wrapper=self._client_wrapper) + return self._prompts + + @property + def scim(self): + if self._scim is None: + from .scim.client import AsyncScimClient # noqa: E402 + + self._scim = AsyncScimClient(client_wrapper=self._client_wrapper) + return self._scim + + @property + def score_configs(self): + if self._score_configs is None: + from .score_configs.client import AsyncScoreConfigsClient # noqa: E402 + + self._score_configs = AsyncScoreConfigsClient( + client_wrapper=self._client_wrapper + ) + return self._score_configs + + @property + def score_v2(self): + if self._score_v2 is None: + from .score_v2.client import AsyncScoreV2Client # noqa: E402 + + self._score_v2 = AsyncScoreV2Client(client_wrapper=self._client_wrapper) + return self._score_v2 + + @property + def score(self): + if self._score is None: + from .score.client import AsyncScoreClient # noqa: E402 + + self._score = AsyncScoreClient(client_wrapper=self._client_wrapper) + return self._score + + @property + def sessions(self): + if self._sessions is None: + from .sessions.client import AsyncSessionsClient # noqa: E402 + + self._sessions = AsyncSessionsClient(client_wrapper=self._client_wrapper) + return self._sessions + + @property + def trace(self): + if self._trace is None: + from .trace.client import AsyncTraceClient # noqa: E402 + + self._trace = AsyncTraceClient(client_wrapper=self._client_wrapper) + return self._trace diff --git a/langfuse/api/comments/__init__.py b/langfuse/api/comments/__init__.py new file mode 100644 index 000000000..0588586c7 --- /dev/null +++ b/langfuse/api/comments/__init__.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import CreateCommentRequest, CreateCommentResponse, GetCommentsResponse +_dynamic_imports: typing.Dict[str, str] = { + "CreateCommentRequest": ".types", + "CreateCommentResponse": ".types", + "GetCommentsResponse": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["CreateCommentRequest", "CreateCommentResponse", "GetCommentsResponse"] diff --git a/langfuse/api/comments/client.py b/langfuse/api/comments/client.py new file mode 100644 index 000000000..f5e92ff36 --- /dev/null +++ b/langfuse/api/comments/client.py @@ -0,0 +1,407 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..commons.types.comment import Comment +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawCommentsClient, RawCommentsClient +from .types.create_comment_response import CreateCommentResponse +from .types.get_comments_response import GetCommentsResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class CommentsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawCommentsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawCommentsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawCommentsClient + """ + return self._raw_client + + def create( + self, + *, + project_id: str, + object_type: str, + object_id: str, + content: str, + author_user_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> CreateCommentResponse: + """ + Create a comment. Comments may be attached to different object types (trace, observation, session, prompt). + + Parameters + ---------- + project_id : str + The id of the project to attach the comment to. + + object_type : str + The type of the object to attach the comment to (trace, observation, session, prompt). + + object_id : str + The id of the object to attach the comment to. If this does not reference a valid existing object, an error will be thrown. + + content : str + The content of the comment. May include markdown. Currently limited to 5000 characters. + + author_user_id : typing.Optional[str] + The id of the user who created the comment. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CreateCommentResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.comments.create( + project_id="projectId", + object_type="objectType", + object_id="objectId", + content="content", + ) + """ + _response = self._raw_client.create( + project_id=project_id, + object_type=object_type, + object_id=object_id, + content=content, + author_user_id=author_user_id, + request_options=request_options, + ) + return _response.data + + def get( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + object_type: typing.Optional[str] = None, + object_id: typing.Optional[str] = None, + author_user_id: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> GetCommentsResponse: + """ + Get all comments + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit + + object_type : typing.Optional[str] + Filter comments by object type (trace, observation, session, prompt). + + object_id : typing.Optional[str] + Filter comments by object id. If objectType is not provided, an error will be thrown. + + author_user_id : typing.Optional[str] + Filter comments by author user id. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetCommentsResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.comments.get() + """ + _response = self._raw_client.get( + page=page, + limit=limit, + object_type=object_type, + object_id=object_id, + author_user_id=author_user_id, + request_options=request_options, + ) + return _response.data + + def get_by_id( + self, + comment_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> Comment: + """ + Get a comment by id + + Parameters + ---------- + comment_id : str + The unique langfuse identifier of a comment + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Comment + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.comments.get_by_id( + comment_id="commentId", + ) + """ + _response = self._raw_client.get_by_id( + comment_id, request_options=request_options + ) + return _response.data + + +class AsyncCommentsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawCommentsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawCommentsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawCommentsClient + """ + return self._raw_client + + async def create( + self, + *, + project_id: str, + object_type: str, + object_id: str, + content: str, + author_user_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> CreateCommentResponse: + """ + Create a comment. Comments may be attached to different object types (trace, observation, session, prompt). + + Parameters + ---------- + project_id : str + The id of the project to attach the comment to. + + object_type : str + The type of the object to attach the comment to (trace, observation, session, prompt). + + object_id : str + The id of the object to attach the comment to. If this does not reference a valid existing object, an error will be thrown. + + content : str + The content of the comment. May include markdown. Currently limited to 5000 characters. + + author_user_id : typing.Optional[str] + The id of the user who created the comment. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CreateCommentResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.comments.create( + project_id="projectId", + object_type="objectType", + object_id="objectId", + content="content", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create( + project_id=project_id, + object_type=object_type, + object_id=object_id, + content=content, + author_user_id=author_user_id, + request_options=request_options, + ) + return _response.data + + async def get( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + object_type: typing.Optional[str] = None, + object_id: typing.Optional[str] = None, + author_user_id: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> GetCommentsResponse: + """ + Get all comments + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit + + object_type : typing.Optional[str] + Filter comments by object type (trace, observation, session, prompt). + + object_id : typing.Optional[str] + Filter comments by object id. If objectType is not provided, an error will be thrown. + + author_user_id : typing.Optional[str] + Filter comments by author user id. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetCommentsResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.comments.get() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get( + page=page, + limit=limit, + object_type=object_type, + object_id=object_id, + author_user_id=author_user_id, + request_options=request_options, + ) + return _response.data + + async def get_by_id( + self, + comment_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> Comment: + """ + Get a comment by id + + Parameters + ---------- + comment_id : str + The unique langfuse identifier of a comment + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Comment + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.comments.get_by_id( + comment_id="commentId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_by_id( + comment_id, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/comments/raw_client.py b/langfuse/api/comments/raw_client.py new file mode 100644 index 000000000..0bb39539a --- /dev/null +++ b/langfuse/api/comments/raw_client.py @@ -0,0 +1,750 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..commons.types.comment import Comment +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.create_comment_response import CreateCommentResponse +from .types.get_comments_response import GetCommentsResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawCommentsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def create( + self, + *, + project_id: str, + object_type: str, + object_id: str, + content: str, + author_user_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[CreateCommentResponse]: + """ + Create a comment. Comments may be attached to different object types (trace, observation, session, prompt). + + Parameters + ---------- + project_id : str + The id of the project to attach the comment to. + + object_type : str + The type of the object to attach the comment to (trace, observation, session, prompt). + + object_id : str + The id of the object to attach the comment to. If this does not reference a valid existing object, an error will be thrown. + + content : str + The content of the comment. May include markdown. Currently limited to 5000 characters. + + author_user_id : typing.Optional[str] + The id of the user who created the comment. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[CreateCommentResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/comments", + method="POST", + json={ + "projectId": project_id, + "objectType": object_type, + "objectId": object_id, + "content": content, + "authorUserId": author_user_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CreateCommentResponse, + parse_obj_as( + type_=CreateCommentResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + object_type: typing.Optional[str] = None, + object_id: typing.Optional[str] = None, + author_user_id: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[GetCommentsResponse]: + """ + Get all comments + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit + + object_type : typing.Optional[str] + Filter comments by object type (trace, observation, session, prompt). + + object_id : typing.Optional[str] + Filter comments by object id. If objectType is not provided, an error will be thrown. + + author_user_id : typing.Optional[str] + Filter comments by author user id. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[GetCommentsResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/comments", + method="GET", + params={ + "page": page, + "limit": limit, + "objectType": object_type, + "objectId": object_id, + "authorUserId": author_user_id, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GetCommentsResponse, + parse_obj_as( + type_=GetCommentsResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_by_id( + self, + comment_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Comment]: + """ + Get a comment by id + + Parameters + ---------- + comment_id : str + The unique langfuse identifier of a comment + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Comment] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/comments/{jsonable_encoder(comment_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Comment, + parse_obj_as( + type_=Comment, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawCommentsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def create( + self, + *, + project_id: str, + object_type: str, + object_id: str, + content: str, + author_user_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[CreateCommentResponse]: + """ + Create a comment. Comments may be attached to different object types (trace, observation, session, prompt). + + Parameters + ---------- + project_id : str + The id of the project to attach the comment to. + + object_type : str + The type of the object to attach the comment to (trace, observation, session, prompt). + + object_id : str + The id of the object to attach the comment to. If this does not reference a valid existing object, an error will be thrown. + + content : str + The content of the comment. May include markdown. Currently limited to 5000 characters. + + author_user_id : typing.Optional[str] + The id of the user who created the comment. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[CreateCommentResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/comments", + method="POST", + json={ + "projectId": project_id, + "objectType": object_type, + "objectId": object_id, + "content": content, + "authorUserId": author_user_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CreateCommentResponse, + parse_obj_as( + type_=CreateCommentResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + object_type: typing.Optional[str] = None, + object_id: typing.Optional[str] = None, + author_user_id: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[GetCommentsResponse]: + """ + Get all comments + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit + + object_type : typing.Optional[str] + Filter comments by object type (trace, observation, session, prompt). + + object_id : typing.Optional[str] + Filter comments by object id. If objectType is not provided, an error will be thrown. + + author_user_id : typing.Optional[str] + Filter comments by author user id. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[GetCommentsResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/comments", + method="GET", + params={ + "page": page, + "limit": limit, + "objectType": object_type, + "objectId": object_id, + "authorUserId": author_user_id, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GetCommentsResponse, + parse_obj_as( + type_=GetCommentsResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_by_id( + self, + comment_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Comment]: + """ + Get a comment by id + + Parameters + ---------- + comment_id : str + The unique langfuse identifier of a comment + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Comment] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/comments/{jsonable_encoder(comment_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Comment, + parse_obj_as( + type_=Comment, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/comments/types/__init__.py b/langfuse/api/comments/types/__init__.py new file mode 100644 index 000000000..4936025a0 --- /dev/null +++ b/langfuse/api/comments/types/__init__.py @@ -0,0 +1,46 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .create_comment_request import CreateCommentRequest + from .create_comment_response import CreateCommentResponse + from .get_comments_response import GetCommentsResponse +_dynamic_imports: typing.Dict[str, str] = { + "CreateCommentRequest": ".create_comment_request", + "CreateCommentResponse": ".create_comment_response", + "GetCommentsResponse": ".get_comments_response", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["CreateCommentRequest", "CreateCommentResponse", "GetCommentsResponse"] diff --git a/langfuse/api/comments/types/create_comment_request.py b/langfuse/api/comments/types/create_comment_request.py new file mode 100644 index 000000000..1d5f717c1 --- /dev/null +++ b/langfuse/api/comments/types/create_comment_request.py @@ -0,0 +1,54 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class CreateCommentRequest(UniversalBaseModel): + project_id: typing_extensions.Annotated[str, FieldMetadata(alias="projectId")] = ( + pydantic.Field() + ) + """ + The id of the project to attach the comment to. + """ + + object_type: typing_extensions.Annotated[str, FieldMetadata(alias="objectType")] = ( + pydantic.Field() + ) + """ + The type of the object to attach the comment to (trace, observation, session, prompt). + """ + + object_id: typing_extensions.Annotated[str, FieldMetadata(alias="objectId")] = ( + pydantic.Field() + ) + """ + The id of the object to attach the comment to. If this does not reference a valid existing object, an error will be thrown. + """ + + content: str = pydantic.Field() + """ + The content of the comment. May include markdown. Currently limited to 5000 characters. + """ + + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = pydantic.Field(default=None) + """ + The id of the user who created the comment. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/comments/types/create_comment_response.py b/langfuse/api/comments/types/create_comment_response.py new file mode 100644 index 000000000..fd7ed95b1 --- /dev/null +++ b/langfuse/api/comments/types/create_comment_response.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class CreateCommentResponse(UniversalBaseModel): + id: str = pydantic.Field() + """ + The id of the created object in Langfuse + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/comments/types/get_comments_response.py b/langfuse/api/comments/types/get_comments_response.py new file mode 100644 index 000000000..a919bd893 --- /dev/null +++ b/langfuse/api/comments/types/get_comments_response.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.comment import Comment +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse + + +class GetCommentsResponse(UniversalBaseModel): + data: typing.List[Comment] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/__init__.py b/langfuse/api/commons/__init__.py new file mode 100644 index 000000000..273e6c76c --- /dev/null +++ b/langfuse/api/commons/__init__.py @@ -0,0 +1,198 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + BaseScore, + BaseScoreV1, + BooleanScore, + BooleanScoreV1, + CategoricalScore, + CategoricalScoreV1, + Comment, + CommentObjectType, + ConfigCategory, + CreateScoreValue, + Dataset, + DatasetItem, + DatasetRun, + DatasetRunItem, + DatasetRunWithItems, + DatasetStatus, + MapValue, + Model, + ModelPrice, + ModelUsageUnit, + NumericScore, + NumericScoreV1, + Observation, + ObservationLevel, + ObservationsView, + PricingTier, + PricingTierCondition, + PricingTierInput, + PricingTierOperator, + Score, + ScoreConfig, + ScoreDataType, + ScoreSource, + ScoreV1, + ScoreV1_Boolean, + ScoreV1_Categorical, + ScoreV1_Numeric, + Score_Boolean, + Score_Categorical, + Score_Numeric, + Session, + SessionWithTraces, + Trace, + TraceWithDetails, + TraceWithFullDetails, + Usage, + ) + from .errors import ( + AccessDeniedError, + Error, + MethodNotAllowedError, + NotFoundError, + UnauthorizedError, + ) +_dynamic_imports: typing.Dict[str, str] = { + "AccessDeniedError": ".errors", + "BaseScore": ".types", + "BaseScoreV1": ".types", + "BooleanScore": ".types", + "BooleanScoreV1": ".types", + "CategoricalScore": ".types", + "CategoricalScoreV1": ".types", + "Comment": ".types", + "CommentObjectType": ".types", + "ConfigCategory": ".types", + "CreateScoreValue": ".types", + "Dataset": ".types", + "DatasetItem": ".types", + "DatasetRun": ".types", + "DatasetRunItem": ".types", + "DatasetRunWithItems": ".types", + "DatasetStatus": ".types", + "Error": ".errors", + "MapValue": ".types", + "MethodNotAllowedError": ".errors", + "Model": ".types", + "ModelPrice": ".types", + "ModelUsageUnit": ".types", + "NotFoundError": ".errors", + "NumericScore": ".types", + "NumericScoreV1": ".types", + "Observation": ".types", + "ObservationLevel": ".types", + "ObservationsView": ".types", + "PricingTier": ".types", + "PricingTierCondition": ".types", + "PricingTierInput": ".types", + "PricingTierOperator": ".types", + "Score": ".types", + "ScoreConfig": ".types", + "ScoreDataType": ".types", + "ScoreSource": ".types", + "ScoreV1": ".types", + "ScoreV1_Boolean": ".types", + "ScoreV1_Categorical": ".types", + "ScoreV1_Numeric": ".types", + "Score_Boolean": ".types", + "Score_Categorical": ".types", + "Score_Numeric": ".types", + "Session": ".types", + "SessionWithTraces": ".types", + "Trace": ".types", + "TraceWithDetails": ".types", + "TraceWithFullDetails": ".types", + "UnauthorizedError": ".errors", + "Usage": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "AccessDeniedError", + "BaseScore", + "BaseScoreV1", + "BooleanScore", + "BooleanScoreV1", + "CategoricalScore", + "CategoricalScoreV1", + "Comment", + "CommentObjectType", + "ConfigCategory", + "CreateScoreValue", + "Dataset", + "DatasetItem", + "DatasetRun", + "DatasetRunItem", + "DatasetRunWithItems", + "DatasetStatus", + "Error", + "MapValue", + "MethodNotAllowedError", + "Model", + "ModelPrice", + "ModelUsageUnit", + "NotFoundError", + "NumericScore", + "NumericScoreV1", + "Observation", + "ObservationLevel", + "ObservationsView", + "PricingTier", + "PricingTierCondition", + "PricingTierInput", + "PricingTierOperator", + "Score", + "ScoreConfig", + "ScoreDataType", + "ScoreSource", + "ScoreV1", + "ScoreV1_Boolean", + "ScoreV1_Categorical", + "ScoreV1_Numeric", + "Score_Boolean", + "Score_Categorical", + "Score_Numeric", + "Session", + "SessionWithTraces", + "Trace", + "TraceWithDetails", + "TraceWithFullDetails", + "UnauthorizedError", + "Usage", +] diff --git a/langfuse/api/commons/errors/__init__.py b/langfuse/api/commons/errors/__init__.py new file mode 100644 index 000000000..c633139f0 --- /dev/null +++ b/langfuse/api/commons/errors/__init__.py @@ -0,0 +1,56 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .access_denied_error import AccessDeniedError + from .error import Error + from .method_not_allowed_error import MethodNotAllowedError + from .not_found_error import NotFoundError + from .unauthorized_error import UnauthorizedError +_dynamic_imports: typing.Dict[str, str] = { + "AccessDeniedError": ".access_denied_error", + "Error": ".error", + "MethodNotAllowedError": ".method_not_allowed_error", + "NotFoundError": ".not_found_error", + "UnauthorizedError": ".unauthorized_error", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "AccessDeniedError", + "Error", + "MethodNotAllowedError", + "NotFoundError", + "UnauthorizedError", +] diff --git a/langfuse/api/commons/errors/access_denied_error.py b/langfuse/api/commons/errors/access_denied_error.py new file mode 100644 index 000000000..156403fb7 --- /dev/null +++ b/langfuse/api/commons/errors/access_denied_error.py @@ -0,0 +1,12 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ...core.api_error import ApiError + + +class AccessDeniedError(ApiError): + def __init__( + self, body: typing.Any, headers: typing.Optional[typing.Dict[str, str]] = None + ): + super().__init__(status_code=403, headers=headers, body=body) diff --git a/langfuse/api/commons/errors/error.py b/langfuse/api/commons/errors/error.py new file mode 100644 index 000000000..5a8bd9639 --- /dev/null +++ b/langfuse/api/commons/errors/error.py @@ -0,0 +1,12 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ...core.api_error import ApiError + + +class Error(ApiError): + def __init__( + self, body: typing.Any, headers: typing.Optional[typing.Dict[str, str]] = None + ): + super().__init__(status_code=400, headers=headers, body=body) diff --git a/langfuse/api/commons/errors/method_not_allowed_error.py b/langfuse/api/commons/errors/method_not_allowed_error.py new file mode 100644 index 000000000..436dd29dd --- /dev/null +++ b/langfuse/api/commons/errors/method_not_allowed_error.py @@ -0,0 +1,12 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ...core.api_error import ApiError + + +class MethodNotAllowedError(ApiError): + def __init__( + self, body: typing.Any, headers: typing.Optional[typing.Dict[str, str]] = None + ): + super().__init__(status_code=405, headers=headers, body=body) diff --git a/langfuse/api/commons/errors/not_found_error.py b/langfuse/api/commons/errors/not_found_error.py new file mode 100644 index 000000000..66b5bfc55 --- /dev/null +++ b/langfuse/api/commons/errors/not_found_error.py @@ -0,0 +1,12 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ...core.api_error import ApiError + + +class NotFoundError(ApiError): + def __init__( + self, body: typing.Any, headers: typing.Optional[typing.Dict[str, str]] = None + ): + super().__init__(status_code=404, headers=headers, body=body) diff --git a/langfuse/api/commons/errors/unauthorized_error.py b/langfuse/api/commons/errors/unauthorized_error.py new file mode 100644 index 000000000..e71a01c5d --- /dev/null +++ b/langfuse/api/commons/errors/unauthorized_error.py @@ -0,0 +1,12 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ...core.api_error import ApiError + + +class UnauthorizedError(ApiError): + def __init__( + self, body: typing.Any, headers: typing.Optional[typing.Dict[str, str]] = None + ): + super().__init__(status_code=401, headers=headers, body=body) diff --git a/langfuse/api/commons/types/__init__.py b/langfuse/api/commons/types/__init__.py new file mode 100644 index 000000000..f4ebf4317 --- /dev/null +++ b/langfuse/api/commons/types/__init__.py @@ -0,0 +1,173 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .base_score import BaseScore + from .base_score_v1 import BaseScoreV1 + from .boolean_score import BooleanScore + from .boolean_score_v1 import BooleanScoreV1 + from .categorical_score import CategoricalScore + from .categorical_score_v1 import CategoricalScoreV1 + from .comment import Comment + from .comment_object_type import CommentObjectType + from .config_category import ConfigCategory + from .create_score_value import CreateScoreValue + from .dataset import Dataset + from .dataset_item import DatasetItem + from .dataset_run import DatasetRun + from .dataset_run_item import DatasetRunItem + from .dataset_run_with_items import DatasetRunWithItems + from .dataset_status import DatasetStatus + from .map_value import MapValue + from .model import Model + from .model_price import ModelPrice + from .model_usage_unit import ModelUsageUnit + from .numeric_score import NumericScore + from .numeric_score_v1 import NumericScoreV1 + from .observation import Observation + from .observation_level import ObservationLevel + from .observations_view import ObservationsView + from .pricing_tier import PricingTier + from .pricing_tier_condition import PricingTierCondition + from .pricing_tier_input import PricingTierInput + from .pricing_tier_operator import PricingTierOperator + from .score import Score, Score_Boolean, Score_Categorical, Score_Numeric + from .score_config import ScoreConfig + from .score_data_type import ScoreDataType + from .score_source import ScoreSource + from .score_v1 import ScoreV1, ScoreV1_Boolean, ScoreV1_Categorical, ScoreV1_Numeric + from .session import Session + from .session_with_traces import SessionWithTraces + from .trace import Trace + from .trace_with_details import TraceWithDetails + from .trace_with_full_details import TraceWithFullDetails + from .usage import Usage +_dynamic_imports: typing.Dict[str, str] = { + "BaseScore": ".base_score", + "BaseScoreV1": ".base_score_v1", + "BooleanScore": ".boolean_score", + "BooleanScoreV1": ".boolean_score_v1", + "CategoricalScore": ".categorical_score", + "CategoricalScoreV1": ".categorical_score_v1", + "Comment": ".comment", + "CommentObjectType": ".comment_object_type", + "ConfigCategory": ".config_category", + "CreateScoreValue": ".create_score_value", + "Dataset": ".dataset", + "DatasetItem": ".dataset_item", + "DatasetRun": ".dataset_run", + "DatasetRunItem": ".dataset_run_item", + "DatasetRunWithItems": ".dataset_run_with_items", + "DatasetStatus": ".dataset_status", + "MapValue": ".map_value", + "Model": ".model", + "ModelPrice": ".model_price", + "ModelUsageUnit": ".model_usage_unit", + "NumericScore": ".numeric_score", + "NumericScoreV1": ".numeric_score_v1", + "Observation": ".observation", + "ObservationLevel": ".observation_level", + "ObservationsView": ".observations_view", + "PricingTier": ".pricing_tier", + "PricingTierCondition": ".pricing_tier_condition", + "PricingTierInput": ".pricing_tier_input", + "PricingTierOperator": ".pricing_tier_operator", + "Score": ".score", + "ScoreConfig": ".score_config", + "ScoreDataType": ".score_data_type", + "ScoreSource": ".score_source", + "ScoreV1": ".score_v1", + "ScoreV1_Boolean": ".score_v1", + "ScoreV1_Categorical": ".score_v1", + "ScoreV1_Numeric": ".score_v1", + "Score_Boolean": ".score", + "Score_Categorical": ".score", + "Score_Numeric": ".score", + "Session": ".session", + "SessionWithTraces": ".session_with_traces", + "Trace": ".trace", + "TraceWithDetails": ".trace_with_details", + "TraceWithFullDetails": ".trace_with_full_details", + "Usage": ".usage", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "BaseScore", + "BaseScoreV1", + "BooleanScore", + "BooleanScoreV1", + "CategoricalScore", + "CategoricalScoreV1", + "Comment", + "CommentObjectType", + "ConfigCategory", + "CreateScoreValue", + "Dataset", + "DatasetItem", + "DatasetRun", + "DatasetRunItem", + "DatasetRunWithItems", + "DatasetStatus", + "MapValue", + "Model", + "ModelPrice", + "ModelUsageUnit", + "NumericScore", + "NumericScoreV1", + "Observation", + "ObservationLevel", + "ObservationsView", + "PricingTier", + "PricingTierCondition", + "PricingTierInput", + "PricingTierOperator", + "Score", + "ScoreConfig", + "ScoreDataType", + "ScoreSource", + "ScoreV1", + "ScoreV1_Boolean", + "ScoreV1_Categorical", + "ScoreV1_Numeric", + "Score_Boolean", + "Score_Categorical", + "Score_Numeric", + "Session", + "SessionWithTraces", + "Trace", + "TraceWithDetails", + "TraceWithFullDetails", + "Usage", +] diff --git a/langfuse/api/commons/types/base_score.py b/langfuse/api/commons/types/base_score.py new file mode 100644 index 000000000..28618ea70 --- /dev/null +++ b/langfuse/api/commons/types/base_score.py @@ -0,0 +1,69 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .score_source import ScoreSource + + +class BaseScore(UniversalBaseModel): + id: str + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = None + session_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sessionId") + ] = None + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + dataset_run_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="datasetRunId") + ] = None + name: str + source: ScoreSource + timestamp: dt.datetime + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = pydantic.Field(default=None) + """ + Reference a score config on a score. When set, config and score name must be equal and value must comply to optionally defined numerical range + """ + + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = pydantic.Field(default=None) + """ + The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. + """ + + environment: typing.Optional[str] = pydantic.Field(default=None) + """ + The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/base_score_v1.py b/langfuse/api/commons/types/base_score_v1.py new file mode 100644 index 000000000..8cd9470fa --- /dev/null +++ b/langfuse/api/commons/types/base_score_v1.py @@ -0,0 +1,61 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .score_source import ScoreSource + + +class BaseScoreV1(UniversalBaseModel): + id: str + trace_id: typing_extensions.Annotated[str, FieldMetadata(alias="traceId")] + name: str + source: ScoreSource + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + timestamp: dt.datetime + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = pydantic.Field(default=None) + """ + Reference a score config on a score. When set, config and score name must be equal and value must comply to optionally defined numerical range + """ + + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = pydantic.Field(default=None) + """ + The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. + """ + + environment: typing.Optional[str] = pydantic.Field(default=None) + """ + The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/boolean_score.py b/langfuse/api/commons/types/boolean_score.py new file mode 100644 index 000000000..106e45896 --- /dev/null +++ b/langfuse/api/commons/types/boolean_score.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .base_score import BaseScore + + +class BooleanScore(BaseScore): + value: float = pydantic.Field() + """ + The numeric value of the score. Equals 1 for "True" and 0 for "False" + """ + + string_value: typing_extensions.Annotated[ + str, FieldMetadata(alias="stringValue") + ] = pydantic.Field() + """ + The string representation of the score value. Is inferred from the numeric value and equals "True" or "False" + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/boolean_score_v1.py b/langfuse/api/commons/types/boolean_score_v1.py new file mode 100644 index 000000000..e024f6260 --- /dev/null +++ b/langfuse/api/commons/types/boolean_score_v1.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .base_score_v1 import BaseScoreV1 + + +class BooleanScoreV1(BaseScoreV1): + value: float = pydantic.Field() + """ + The numeric value of the score. Equals 1 for "True" and 0 for "False" + """ + + string_value: typing_extensions.Annotated[ + str, FieldMetadata(alias="stringValue") + ] = pydantic.Field() + """ + The string representation of the score value. Is inferred from the numeric value and equals "True" or "False" + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/categorical_score.py b/langfuse/api/commons/types/categorical_score.py new file mode 100644 index 000000000..d8a2a671d --- /dev/null +++ b/langfuse/api/commons/types/categorical_score.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .base_score import BaseScore + + +class CategoricalScore(BaseScore): + value: float = pydantic.Field() + """ + Represents the numeric category mapping of the stringValue. If no config is linked, defaults to 0. + """ + + string_value: typing_extensions.Annotated[ + str, FieldMetadata(alias="stringValue") + ] = pydantic.Field() + """ + The string representation of the score value. If no config is linked, can be any string. Otherwise, must map to a config category + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/categorical_score_v1.py b/langfuse/api/commons/types/categorical_score_v1.py new file mode 100644 index 000000000..e6454cc66 --- /dev/null +++ b/langfuse/api/commons/types/categorical_score_v1.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .base_score_v1 import BaseScoreV1 + + +class CategoricalScoreV1(BaseScoreV1): + value: float = pydantic.Field() + """ + Represents the numeric category mapping of the stringValue. If no config is linked, defaults to 0. + """ + + string_value: typing_extensions.Annotated[ + str, FieldMetadata(alias="stringValue") + ] = pydantic.Field() + """ + The string representation of the score value. If no config is linked, can be any string. Otherwise, must map to a config category + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/comment.py b/langfuse/api/commons/types/comment.py new file mode 100644 index 000000000..699efdce0 --- /dev/null +++ b/langfuse/api/commons/types/comment.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .comment_object_type import CommentObjectType + + +class Comment(UniversalBaseModel): + id: str + project_id: typing_extensions.Annotated[str, FieldMetadata(alias="projectId")] + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + object_type: typing_extensions.Annotated[ + CommentObjectType, FieldMetadata(alias="objectType") + ] + object_id: typing_extensions.Annotated[str, FieldMetadata(alias="objectId")] + content: str + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/comment_object_type.py b/langfuse/api/commons/types/comment_object_type.py new file mode 100644 index 000000000..9677c4293 --- /dev/null +++ b/langfuse/api/commons/types/comment_object_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CommentObjectType = typing.Union[ + typing.Literal["TRACE", "OBSERVATION", "SESSION", "PROMPT"], typing.Any +] diff --git a/langfuse/api/commons/types/config_category.py b/langfuse/api/commons/types/config_category.py new file mode 100644 index 000000000..c888d8e73 --- /dev/null +++ b/langfuse/api/commons/types/config_category.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ConfigCategory(UniversalBaseModel): + value: float + label: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/resources/commons/types/create_score_value.py b/langfuse/api/commons/types/create_score_value.py similarity index 100% rename from langfuse/api/resources/commons/types/create_score_value.py rename to langfuse/api/commons/types/create_score_value.py diff --git a/langfuse/api/commons/types/dataset.py b/langfuse/api/commons/types/dataset.py new file mode 100644 index 000000000..baea2c07f --- /dev/null +++ b/langfuse/api/commons/types/dataset.py @@ -0,0 +1,48 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class Dataset(UniversalBaseModel): + id: str + name: str + description: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + input_schema: typing_extensions.Annotated[ + typing.Optional[typing.Any], FieldMetadata(alias="inputSchema") + ] = pydantic.Field(default=None) + """ + JSON Schema for validating dataset item inputs + """ + + expected_output_schema: typing_extensions.Annotated[ + typing.Optional[typing.Any], FieldMetadata(alias="expectedOutputSchema") + ] = pydantic.Field(default=None) + """ + JSON Schema for validating dataset item expected outputs + """ + + project_id: typing_extensions.Annotated[str, FieldMetadata(alias="projectId")] + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/dataset_item.py b/langfuse/api/commons/types/dataset_item.py new file mode 100644 index 000000000..8cbc28578 --- /dev/null +++ b/langfuse/api/commons/types/dataset_item.py @@ -0,0 +1,45 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .dataset_status import DatasetStatus + + +class DatasetItem(UniversalBaseModel): + id: str + status: DatasetStatus + input: typing.Optional[typing.Any] = None + expected_output: typing_extensions.Annotated[ + typing.Optional[typing.Any], FieldMetadata(alias="expectedOutput") + ] = None + metadata: typing.Optional[typing.Any] = None + source_trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sourceTraceId") + ] = None + source_observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sourceObservationId") + ] = None + dataset_id: typing_extensions.Annotated[str, FieldMetadata(alias="datasetId")] + dataset_name: typing_extensions.Annotated[str, FieldMetadata(alias="datasetName")] + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/dataset_run.py b/langfuse/api/commons/types/dataset_run.py new file mode 100644 index 000000000..c5e377632 --- /dev/null +++ b/langfuse/api/commons/types/dataset_run.py @@ -0,0 +1,70 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class DatasetRun(UniversalBaseModel): + id: str = pydantic.Field() + """ + Unique identifier of the dataset run + """ + + name: str = pydantic.Field() + """ + Name of the dataset run + """ + + description: typing.Optional[str] = pydantic.Field(default=None) + """ + Description of the run + """ + + metadata: typing.Optional[typing.Any] = pydantic.Field(default=None) + """ + Metadata of the dataset run + """ + + dataset_id: typing_extensions.Annotated[str, FieldMetadata(alias="datasetId")] = ( + pydantic.Field() + ) + """ + Id of the associated dataset + """ + + dataset_name: typing_extensions.Annotated[ + str, FieldMetadata(alias="datasetName") + ] = pydantic.Field() + """ + Name of the associated dataset + """ + + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] = pydantic.Field() + """ + The date and time when the dataset run was created + """ + + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] = pydantic.Field() + """ + The date and time when the dataset run was last updated + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/dataset_run_item.py b/langfuse/api/commons/types/dataset_run_item.py new file mode 100644 index 000000000..1a736fdc9 --- /dev/null +++ b/langfuse/api/commons/types/dataset_run_item.py @@ -0,0 +1,43 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class DatasetRunItem(UniversalBaseModel): + id: str + dataset_run_id: typing_extensions.Annotated[ + str, FieldMetadata(alias="datasetRunId") + ] + dataset_run_name: typing_extensions.Annotated[ + str, FieldMetadata(alias="datasetRunName") + ] + dataset_item_id: typing_extensions.Annotated[ + str, FieldMetadata(alias="datasetItemId") + ] + trace_id: typing_extensions.Annotated[str, FieldMetadata(alias="traceId")] + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/dataset_run_with_items.py b/langfuse/api/commons/types/dataset_run_with_items.py new file mode 100644 index 000000000..5297dbb4a --- /dev/null +++ b/langfuse/api/commons/types/dataset_run_with_items.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .dataset_run import DatasetRun +from .dataset_run_item import DatasetRunItem + + +class DatasetRunWithItems(DatasetRun): + dataset_run_items: typing_extensions.Annotated[ + typing.List[DatasetRunItem], FieldMetadata(alias="datasetRunItems") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/dataset_status.py b/langfuse/api/commons/types/dataset_status.py new file mode 100644 index 000000000..f09c011d2 --- /dev/null +++ b/langfuse/api/commons/types/dataset_status.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +DatasetStatus = typing.Union[typing.Literal["ACTIVE", "ARCHIVED"], typing.Any] diff --git a/langfuse/api/resources/commons/types/map_value.py b/langfuse/api/commons/types/map_value.py similarity index 100% rename from langfuse/api/resources/commons/types/map_value.py rename to langfuse/api/commons/types/map_value.py diff --git a/langfuse/api/resources/commons/types/model.py b/langfuse/api/commons/types/model.py similarity index 55% rename from langfuse/api/resources/commons/types/model.py rename to langfuse/api/commons/types/model.py index 1b83c2696..f17ae6a2b 100644 --- a/langfuse/api/resources/commons/types/model.py +++ b/langfuse/api/commons/types/model.py @@ -3,14 +3,16 @@ import datetime as dt import typing -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata from .model_price import ModelPrice from .model_usage_unit import ModelUsageUnit from .pricing_tier import PricingTier -class Model(pydantic_v1.BaseModel): +class Model(UniversalBaseModel): """ Model definition used for transforming usage into USD cost and/or tokenization. @@ -24,70 +26,78 @@ class Model(pydantic_v1.BaseModel): """ id: str - model_name: str = pydantic_v1.Field(alias="modelName") + model_name: typing_extensions.Annotated[str, FieldMetadata(alias="modelName")] = ( + pydantic.Field() + ) """ Name of the model definition. If multiple with the same name exist, they are applied in the following order: (1) custom over built-in, (2) newest according to startTime where model.startTime str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/model_price.py b/langfuse/api/commons/types/model_price.py new file mode 100644 index 000000000..2ec43156d --- /dev/null +++ b/langfuse/api/commons/types/model_price.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ModelPrice(UniversalBaseModel): + price: float + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/model_usage_unit.py b/langfuse/api/commons/types/model_usage_unit.py new file mode 100644 index 000000000..6705b47e3 --- /dev/null +++ b/langfuse/api/commons/types/model_usage_unit.py @@ -0,0 +1,10 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ModelUsageUnit = typing.Union[ + typing.Literal[ + "CHARACTERS", "TOKENS", "MILLISECONDS", "SECONDS", "IMAGES", "REQUESTS" + ], + typing.Any, +] diff --git a/langfuse/api/commons/types/numeric_score.py b/langfuse/api/commons/types/numeric_score.py new file mode 100644 index 000000000..47bda6593 --- /dev/null +++ b/langfuse/api/commons/types/numeric_score.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_score import BaseScore + + +class NumericScore(BaseScore): + value: float = pydantic.Field() + """ + The numeric value of the score + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/numeric_score_v1.py b/langfuse/api/commons/types/numeric_score_v1.py new file mode 100644 index 000000000..60f7b45a9 --- /dev/null +++ b/langfuse/api/commons/types/numeric_score_v1.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_score_v1 import BaseScoreV1 + + +class NumericScoreV1(BaseScoreV1): + value: float = pydantic.Field() + """ + The numeric value of the score + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/observation.py b/langfuse/api/commons/types/observation.py new file mode 100644 index 000000000..3500834bd --- /dev/null +++ b/langfuse/api/commons/types/observation.py @@ -0,0 +1,151 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .map_value import MapValue +from .observation_level import ObservationLevel +from .usage import Usage + + +class Observation(UniversalBaseModel): + id: str = pydantic.Field() + """ + The unique identifier of the observation + """ + + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = pydantic.Field(default=None) + """ + The trace ID associated with the observation + """ + + type: str = pydantic.Field() + """ + The type of the observation + """ + + name: typing.Optional[str] = pydantic.Field(default=None) + """ + The name of the observation + """ + + start_time: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="startTime") + ] = pydantic.Field() + """ + The start time of the observation + """ + + end_time: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="endTime") + ] = pydantic.Field(default=None) + """ + The end time of the observation. + """ + + completion_start_time: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="completionStartTime") + ] = pydantic.Field(default=None) + """ + The completion start time of the observation + """ + + model: typing.Optional[str] = pydantic.Field(default=None) + """ + The model used for the observation + """ + + model_parameters: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, MapValue]], + FieldMetadata(alias="modelParameters"), + ] = pydantic.Field(default=None) + """ + The parameters of the model used for the observation + """ + + input: typing.Optional[typing.Any] = pydantic.Field(default=None) + """ + The input data of the observation + """ + + version: typing.Optional[str] = pydantic.Field(default=None) + """ + The version of the observation + """ + + metadata: typing.Optional[typing.Any] = pydantic.Field(default=None) + """ + Additional metadata of the observation + """ + + output: typing.Optional[typing.Any] = pydantic.Field(default=None) + """ + The output data of the observation + """ + + usage: typing.Optional[Usage] = pydantic.Field(default=None) + """ + (Deprecated. Use usageDetails and costDetails instead.) The usage data of the observation + """ + + level: ObservationLevel = pydantic.Field() + """ + The level of the observation + """ + + status_message: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="statusMessage") + ] = pydantic.Field(default=None) + """ + The status message of the observation + """ + + parent_observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="parentObservationId") + ] = pydantic.Field(default=None) + """ + The parent observation ID + """ + + prompt_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="promptId") + ] = pydantic.Field(default=None) + """ + The prompt ID associated with the observation + """ + + usage_details: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, int]], FieldMetadata(alias="usageDetails") + ] = pydantic.Field(default=None) + """ + The usage details of the observation. Key is the name of the usage metric, value is the number of units consumed. The total key is the sum of all (non-total) usage metrics or the total value ingested. + """ + + cost_details: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, float]], FieldMetadata(alias="costDetails") + ] = pydantic.Field(default=None) + """ + The cost details of the observation. Key is the name of the cost metric, value is the cost in USD. The total key is the sum of all (non-total) cost metrics or the total value ingested. + """ + + environment: typing.Optional[str] = pydantic.Field(default=None) + """ + The environment from which this observation originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/observation_level.py b/langfuse/api/commons/types/observation_level.py new file mode 100644 index 000000000..8a42779ca --- /dev/null +++ b/langfuse/api/commons/types/observation_level.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ObservationLevel = typing.Union[ + typing.Literal["DEBUG", "DEFAULT", "WARNING", "ERROR"], typing.Any +] diff --git a/langfuse/api/commons/types/observations_view.py b/langfuse/api/commons/types/observations_view.py new file mode 100644 index 000000000..6f375c925 --- /dev/null +++ b/langfuse/api/commons/types/observations_view.py @@ -0,0 +1,97 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .observation import Observation + + +class ObservationsView(Observation): + prompt_name: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="promptName") + ] = pydantic.Field(default=None) + """ + The name of the prompt associated with the observation + """ + + prompt_version: typing_extensions.Annotated[ + typing.Optional[int], FieldMetadata(alias="promptVersion") + ] = pydantic.Field(default=None) + """ + The version of the prompt associated with the observation + """ + + model_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="modelId") + ] = pydantic.Field(default=None) + """ + The unique identifier of the model + """ + + input_price: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="inputPrice") + ] = pydantic.Field(default=None) + """ + The price of the input in USD + """ + + output_price: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="outputPrice") + ] = pydantic.Field(default=None) + """ + The price of the output in USD. + """ + + total_price: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="totalPrice") + ] = pydantic.Field(default=None) + """ + The total price in USD. + """ + + calculated_input_cost: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="calculatedInputCost") + ] = pydantic.Field(default=None) + """ + (Deprecated. Use usageDetails and costDetails instead.) The calculated cost of the input in USD + """ + + calculated_output_cost: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="calculatedOutputCost") + ] = pydantic.Field(default=None) + """ + (Deprecated. Use usageDetails and costDetails instead.) The calculated cost of the output in USD + """ + + calculated_total_cost: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="calculatedTotalCost") + ] = pydantic.Field(default=None) + """ + (Deprecated. Use usageDetails and costDetails instead.) The calculated total cost in USD + """ + + latency: typing.Optional[float] = pydantic.Field(default=None) + """ + The latency in seconds. + """ + + time_to_first_token: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="timeToFirstToken") + ] = pydantic.Field(default=None) + """ + The time to the first token in seconds + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/resources/commons/types/pricing_tier.py b/langfuse/api/commons/types/pricing_tier.py similarity index 66% rename from langfuse/api/resources/commons/types/pricing_tier.py rename to langfuse/api/commons/types/pricing_tier.py index 031d142c0..3a51f54ee 100644 --- a/langfuse/api/resources/commons/types/pricing_tier.py +++ b/langfuse/api/commons/types/pricing_tier.py @@ -1,14 +1,15 @@ # This file was auto-generated by Fern from our API Definition. -import datetime as dt import typing -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata from .pricing_tier_condition import PricingTierCondition -class PricingTier(pydantic_v1.BaseModel): +class PricingTier(UniversalBaseModel): """ Pricing tier definition with conditional pricing based on usage thresholds. @@ -29,19 +30,21 @@ class PricingTier(pydantic_v1.BaseModel): Every model must have exactly one default tier to ensure cost calculation always succeeds. """ - id: str = pydantic_v1.Field() + id: str = pydantic.Field() """ Unique identifier for the pricing tier """ - name: str = pydantic_v1.Field() + name: str = pydantic.Field() """ Name of the pricing tier for display and identification purposes. Examples: "Standard", "High Volume Tier", "Large Context", "Extended Context Tier" """ - is_default: bool = pydantic_v1.Field(alias="isDefault") + is_default: typing_extensions.Annotated[bool, FieldMetadata(alias="isDefault")] = ( + pydantic.Field() + ) """ Whether this is the default tier. Every model must have exactly one default tier with priority 0 and no conditions. @@ -49,7 +52,7 @@ class PricingTier(pydantic_v1.BaseModel): It typically represents the base pricing for standard usage patterns. """ - priority: int = pydantic_v1.Field() + priority: int = pydantic.Field() """ Priority for tier matching evaluation. Lower numbers = higher priority (evaluated first). @@ -63,7 +66,7 @@ class PricingTier(pydantic_v1.BaseModel): This ensures more specific conditions are checked before general ones. """ - conditions: typing.List[PricingTierCondition] = pydantic_v1.Field() + conditions: typing.List[PricingTierCondition] = pydantic.Field() """ Array of conditions that must ALL be met for this tier to match (AND logic). @@ -73,7 +76,7 @@ class PricingTier(pydantic_v1.BaseModel): Multiple conditions enable complex matching scenarios (e.g., "high input tokens AND low output tokens"). """ - prices: typing.Dict[str, float] = pydantic_v1.Field() + prices: typing.Dict[str, float] = pydantic.Field() """ Prices (USD) by usage type for this tier. @@ -83,35 +86,13 @@ class PricingTier(pydantic_v1.BaseModel): Example: {"input": 0.000003, "output": 0.000015} means $3 per million input tokens and $15 per million output tokens. """ - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/resources/commons/types/pricing_tier_condition.py b/langfuse/api/commons/types/pricing_tier_condition.py similarity index 57% rename from langfuse/api/resources/commons/types/pricing_tier_condition.py rename to langfuse/api/commons/types/pricing_tier_condition.py index 8b89fe116..54ae6d226 100644 --- a/langfuse/api/resources/commons/types/pricing_tier_condition.py +++ b/langfuse/api/commons/types/pricing_tier_condition.py @@ -1,14 +1,15 @@ # This file was auto-generated by Fern from our API Definition. -import datetime as dt import typing -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata from .pricing_tier_operator import PricingTierOperator -class PricingTierCondition(pydantic_v1.BaseModel): +class PricingTierCondition(UniversalBaseModel): """ Condition for matching a pricing tier based on usage details. Used to implement tiered pricing models where costs vary based on usage thresholds. @@ -24,7 +25,9 @@ class PricingTierCondition(pydantic_v1.BaseModel): - Volume-based pricing: Different rates based on total request or token count """ - usage_detail_pattern: str = pydantic_v1.Field(alias="usageDetailPattern") + usage_detail_pattern: typing_extensions.Annotated[ + str, FieldMetadata(alias="usageDetailPattern") + ] = pydantic.Field() """ Regex pattern to match against usage detail keys. All matching keys' values are summed for threshold comparison. @@ -36,7 +39,7 @@ class PricingTierCondition(pydantic_v1.BaseModel): The pattern is case-insensitive by default. If no keys match, the sum is treated as zero. """ - operator: PricingTierOperator = pydantic_v1.Field() + operator: PricingTierOperator = pydantic.Field() """ Comparison operator to apply between the summed value and the threshold. @@ -48,45 +51,25 @@ class PricingTierCondition(pydantic_v1.BaseModel): - neq: not equal (sum != threshold) """ - value: float = pydantic_v1.Field() + value: float = pydantic.Field() """ Threshold value for comparison. For token-based pricing, this is typically the token count threshold (e.g., 200000 for a 200K token threshold). """ - case_sensitive: bool = pydantic_v1.Field(alias="caseSensitive") + case_sensitive: typing_extensions.Annotated[ + bool, FieldMetadata(alias="caseSensitive") + ] = pydantic.Field() """ Whether the regex pattern matching is case-sensitive. Default is false (case-insensitive matching). """ - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/resources/commons/types/pricing_tier_input.py b/langfuse/api/commons/types/pricing_tier_input.py similarity index 59% rename from langfuse/api/resources/commons/types/pricing_tier_input.py rename to langfuse/api/commons/types/pricing_tier_input.py index 00dfdb37b..90d62e4b6 100644 --- a/langfuse/api/resources/commons/types/pricing_tier_input.py +++ b/langfuse/api/commons/types/pricing_tier_input.py @@ -1,14 +1,15 @@ # This file was auto-generated by Fern from our API Definition. -import datetime as dt import typing -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata from .pricing_tier_condition import PricingTierCondition -class PricingTierInput(pydantic_v1.BaseModel): +class PricingTierInput(UniversalBaseModel): """ Input schema for creating a pricing tier. The tier ID will be automatically generated server-side. @@ -21,14 +22,16 @@ class PricingTierInput(pydantic_v1.BaseModel): See PricingTier for detailed information about how tiers work and why they're useful. """ - name: str = pydantic_v1.Field() + name: str = pydantic.Field() """ Name of the pricing tier for display and identification purposes. Must be unique within the model. Common patterns: "Standard", "High Volume Tier", "Extended Context" """ - is_default: bool = pydantic_v1.Field(alias="isDefault") + is_default: typing_extensions.Annotated[bool, FieldMetadata(alias="isDefault")] = ( + pydantic.Field() + ) """ Whether this is the default tier. Exactly one tier per model must be marked as default. @@ -40,7 +43,7 @@ class PricingTierInput(pydantic_v1.BaseModel): The default tier acts as a fallback when no conditional tiers match. """ - priority: int = pydantic_v1.Field() + priority: int = pydantic.Field() """ Priority for tier matching evaluation. Lower numbers = higher priority (evaluated first). @@ -48,7 +51,7 @@ class PricingTierInput(pydantic_v1.BaseModel): Conditional tiers should use priority 1, 2, 3, etc. based on their specificity. """ - conditions: typing.List[PricingTierCondition] = pydantic_v1.Field() + conditions: typing.List[PricingTierCondition] = pydantic.Field() """ Array of conditions that must ALL be met for this tier to match (AND logic). @@ -58,7 +61,7 @@ class PricingTierInput(pydantic_v1.BaseModel): Each condition specifies a regex pattern, operator, and threshold value for matching against usage details. """ - prices: typing.Dict[str, float] = pydantic_v1.Field() + prices: typing.Dict[str, float] = pydantic.Field() """ Prices (USD) by usage type for this tier. At least one price must be defined. @@ -68,35 +71,13 @@ class PricingTierInput(pydantic_v1.BaseModel): Example: {"input": 0.000003, "output": 0.000015} represents $3 per million input tokens and $15 per million output tokens. """ - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/pricing_tier_operator.py b/langfuse/api/commons/types/pricing_tier_operator.py new file mode 100644 index 000000000..14d4a80eb --- /dev/null +++ b/langfuse/api/commons/types/pricing_tier_operator.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +PricingTierOperator = typing.Union[ + typing.Literal["gt", "gte", "lt", "lte", "eq", "neq"], typing.Any +] diff --git a/langfuse/api/commons/types/score.py b/langfuse/api/commons/types/score.py new file mode 100644 index 000000000..056f1cdea --- /dev/null +++ b/langfuse/api/commons/types/score.py @@ -0,0 +1,176 @@ +# This file was auto-generated by Fern from our API Definition. + +from __future__ import annotations + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .score_source import ScoreSource + + +class Score_Numeric(UniversalBaseModel): + data_type: typing_extensions.Annotated[ + typing.Literal["NUMERIC"], FieldMetadata(alias="dataType") + ] = "NUMERIC" + value: float + id: str + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = None + session_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sessionId") + ] = None + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + dataset_run_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="datasetRunId") + ] = None + name: str + source: ScoreSource + timestamp: dt.datetime + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = None + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = None + environment: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class Score_Categorical(UniversalBaseModel): + data_type: typing_extensions.Annotated[ + typing.Literal["CATEGORICAL"], FieldMetadata(alias="dataType") + ] = "CATEGORICAL" + value: float + string_value: typing_extensions.Annotated[str, FieldMetadata(alias="stringValue")] + id: str + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = None + session_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sessionId") + ] = None + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + dataset_run_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="datasetRunId") + ] = None + name: str + source: ScoreSource + timestamp: dt.datetime + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = None + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = None + environment: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class Score_Boolean(UniversalBaseModel): + data_type: typing_extensions.Annotated[ + typing.Literal["BOOLEAN"], FieldMetadata(alias="dataType") + ] = "BOOLEAN" + value: float + string_value: typing_extensions.Annotated[str, FieldMetadata(alias="stringValue")] + id: str + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = None + session_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sessionId") + ] = None + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + dataset_run_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="datasetRunId") + ] = None + name: str + source: ScoreSource + timestamp: dt.datetime + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = None + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = None + environment: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +Score = typing_extensions.Annotated[ + typing.Union[Score_Numeric, Score_Categorical, Score_Boolean], + pydantic.Field(discriminator="data_type"), +] diff --git a/langfuse/api/commons/types/score_config.py b/langfuse/api/commons/types/score_config.py new file mode 100644 index 000000000..4f52b3679 --- /dev/null +++ b/langfuse/api/commons/types/score_config.py @@ -0,0 +1,70 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .config_category import ConfigCategory +from .score_data_type import ScoreDataType + + +class ScoreConfig(UniversalBaseModel): + """ + Configuration for a score + """ + + id: str + name: str + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + project_id: typing_extensions.Annotated[str, FieldMetadata(alias="projectId")] + data_type: typing_extensions.Annotated[ + ScoreDataType, FieldMetadata(alias="dataType") + ] + is_archived: typing_extensions.Annotated[ + bool, FieldMetadata(alias="isArchived") + ] = pydantic.Field() + """ + Whether the score config is archived. Defaults to false + """ + + min_value: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="minValue") + ] = pydantic.Field(default=None) + """ + Sets minimum value for numerical scores. If not set, the minimum value defaults to -∞ + """ + + max_value: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="maxValue") + ] = pydantic.Field(default=None) + """ + Sets maximum value for numerical scores. If not set, the maximum value defaults to +∞ + """ + + categories: typing.Optional[typing.List[ConfigCategory]] = pydantic.Field( + default=None + ) + """ + Configures custom categories for categorical scores + """ + + description: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/score_data_type.py b/langfuse/api/commons/types/score_data_type.py new file mode 100644 index 000000000..d3be48c06 --- /dev/null +++ b/langfuse/api/commons/types/score_data_type.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ScoreDataType = typing.Union[ + typing.Literal["NUMERIC", "BOOLEAN", "CATEGORICAL"], typing.Any +] diff --git a/langfuse/api/commons/types/score_source.py b/langfuse/api/commons/types/score_source.py new file mode 100644 index 000000000..036918272 --- /dev/null +++ b/langfuse/api/commons/types/score_source.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ScoreSource = typing.Union[typing.Literal["ANNOTATION", "API", "EVAL"], typing.Any] diff --git a/langfuse/api/commons/types/score_v1.py b/langfuse/api/commons/types/score_v1.py new file mode 100644 index 000000000..47a5ec580 --- /dev/null +++ b/langfuse/api/commons/types/score_v1.py @@ -0,0 +1,152 @@ +# This file was auto-generated by Fern from our API Definition. + +from __future__ import annotations + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .score_source import ScoreSource + + +class ScoreV1_Numeric(UniversalBaseModel): + data_type: typing_extensions.Annotated[ + typing.Literal["NUMERIC"], FieldMetadata(alias="dataType") + ] = "NUMERIC" + value: float + id: str + trace_id: typing_extensions.Annotated[str, FieldMetadata(alias="traceId")] + name: str + source: ScoreSource + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + timestamp: dt.datetime + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = None + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = None + environment: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class ScoreV1_Categorical(UniversalBaseModel): + data_type: typing_extensions.Annotated[ + typing.Literal["CATEGORICAL"], FieldMetadata(alias="dataType") + ] = "CATEGORICAL" + value: float + string_value: typing_extensions.Annotated[str, FieldMetadata(alias="stringValue")] + id: str + trace_id: typing_extensions.Annotated[str, FieldMetadata(alias="traceId")] + name: str + source: ScoreSource + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + timestamp: dt.datetime + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = None + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = None + environment: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class ScoreV1_Boolean(UniversalBaseModel): + data_type: typing_extensions.Annotated[ + typing.Literal["BOOLEAN"], FieldMetadata(alias="dataType") + ] = "BOOLEAN" + value: float + string_value: typing_extensions.Annotated[str, FieldMetadata(alias="stringValue")] + id: str + trace_id: typing_extensions.Annotated[str, FieldMetadata(alias="traceId")] + name: str + source: ScoreSource + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + timestamp: dt.datetime + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = None + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = None + environment: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +ScoreV1 = typing_extensions.Annotated[ + typing.Union[ScoreV1_Numeric, ScoreV1_Categorical, ScoreV1_Boolean], + pydantic.Field(discriminator="data_type"), +] diff --git a/langfuse/api/commons/types/session.py b/langfuse/api/commons/types/session.py new file mode 100644 index 000000000..6d4aa1d23 --- /dev/null +++ b/langfuse/api/commons/types/session.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class Session(UniversalBaseModel): + id: str + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + project_id: typing_extensions.Annotated[str, FieldMetadata(alias="projectId")] + environment: typing.Optional[str] = pydantic.Field(default=None) + """ + The environment from which this session originated. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/session_with_traces.py b/langfuse/api/commons/types/session_with_traces.py new file mode 100644 index 000000000..ff33602b8 --- /dev/null +++ b/langfuse/api/commons/types/session_with_traces.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .session import Session +from .trace import Trace + + +class SessionWithTraces(Session): + traces: typing.List[Trace] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/trace.py b/langfuse/api/commons/types/trace.py new file mode 100644 index 000000000..4d02e8eb2 --- /dev/null +++ b/langfuse/api/commons/types/trace.py @@ -0,0 +1,91 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class Trace(UniversalBaseModel): + id: str = pydantic.Field() + """ + The unique identifier of a trace + """ + + timestamp: dt.datetime = pydantic.Field() + """ + The timestamp when the trace was created + """ + + name: typing.Optional[str] = pydantic.Field(default=None) + """ + The name of the trace + """ + + input: typing.Optional[typing.Any] = pydantic.Field(default=None) + """ + The input data of the trace. Can be any JSON. + """ + + output: typing.Optional[typing.Any] = pydantic.Field(default=None) + """ + The output data of the trace. Can be any JSON. + """ + + session_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sessionId") + ] = pydantic.Field(default=None) + """ + The session identifier associated with the trace + """ + + release: typing.Optional[str] = pydantic.Field(default=None) + """ + The release version of the application when the trace was created + """ + + version: typing.Optional[str] = pydantic.Field(default=None) + """ + The version of the trace + """ + + user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="userId") + ] = pydantic.Field(default=None) + """ + The user identifier associated with the trace + """ + + metadata: typing.Optional[typing.Any] = pydantic.Field(default=None) + """ + The metadata associated with the trace. Can be any JSON. + """ + + tags: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + The tags associated with the trace. Can be an array of strings or null. + """ + + public: typing.Optional[bool] = pydantic.Field(default=None) + """ + Public traces are accessible via url without login + """ + + environment: typing.Optional[str] = pydantic.Field(default=None) + """ + The environment from which this trace originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/trace_with_details.py b/langfuse/api/commons/types/trace_with_details.py new file mode 100644 index 000000000..658dbeff4 --- /dev/null +++ b/langfuse/api/commons/types/trace_with_details.py @@ -0,0 +1,51 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .trace import Trace + + +class TraceWithDetails(Trace): + html_path: typing_extensions.Annotated[str, FieldMetadata(alias="htmlPath")] = ( + pydantic.Field() + ) + """ + Path of trace in Langfuse UI + """ + + latency: float = pydantic.Field() + """ + Latency of trace in seconds + """ + + total_cost: typing_extensions.Annotated[float, FieldMetadata(alias="totalCost")] = ( + pydantic.Field() + ) + """ + Cost of trace in USD + """ + + observations: typing.List[str] = pydantic.Field() + """ + List of observation ids + """ + + scores: typing.List[str] = pydantic.Field() + """ + List of score ids + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/trace_with_full_details.py b/langfuse/api/commons/types/trace_with_full_details.py new file mode 100644 index 000000000..00dda3982 --- /dev/null +++ b/langfuse/api/commons/types/trace_with_full_details.py @@ -0,0 +1,53 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .observations_view import ObservationsView +from .score_v1 import ScoreV1 +from .trace import Trace + + +class TraceWithFullDetails(Trace): + html_path: typing_extensions.Annotated[str, FieldMetadata(alias="htmlPath")] = ( + pydantic.Field() + ) + """ + Path of trace in Langfuse UI + """ + + latency: float = pydantic.Field() + """ + Latency of trace in seconds + """ + + total_cost: typing_extensions.Annotated[float, FieldMetadata(alias="totalCost")] = ( + pydantic.Field() + ) + """ + Cost of trace in USD + """ + + observations: typing.List[ObservationsView] = pydantic.Field() + """ + List of observations + """ + + scores: typing.List[ScoreV1] = pydantic.Field() + """ + List of scores + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/commons/types/usage.py b/langfuse/api/commons/types/usage.py new file mode 100644 index 000000000..2e1970661 --- /dev/null +++ b/langfuse/api/commons/types/usage.py @@ -0,0 +1,63 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .model_usage_unit import ModelUsageUnit + + +class Usage(UniversalBaseModel): + """ + (Deprecated. Use usageDetails and costDetails instead.) Standard interface for usage and cost + """ + + input: typing.Optional[int] = pydantic.Field(default=None) + """ + Number of input units (e.g. tokens) + """ + + output: typing.Optional[int] = pydantic.Field(default=None) + """ + Number of output units (e.g. tokens) + """ + + total: typing.Optional[int] = pydantic.Field(default=None) + """ + Defaults to input+output if not set + """ + + unit: typing.Optional[ModelUsageUnit] = None + input_cost: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="inputCost") + ] = pydantic.Field(default=None) + """ + USD input cost + """ + + output_cost: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="outputCost") + ] = pydantic.Field(default=None) + """ + USD output cost + """ + + total_cost: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="totalCost") + ] = pydantic.Field(default=None) + """ + USD total cost, defaults to input+output + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/core/__init__.py b/langfuse/api/core/__init__.py index 58ad52ad2..91742cd87 100644 --- a/langfuse/api/core/__init__.py +++ b/langfuse/api/core/__init__.py @@ -1,30 +1,111 @@ # This file was auto-generated by Fern from our API Definition. -from .api_error import ApiError -from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper -from .datetime_utils import serialize_datetime -from .file import File, convert_file_dict_to_httpx_tuples -from .http_client import AsyncHttpClient, HttpClient -from .jsonable_encoder import jsonable_encoder -from .pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .query_encoder import encode_query -from .remove_none_from_dict import remove_none_from_dict -from .request_options import RequestOptions +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .api_error import ApiError + from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper + from .datetime_utils import serialize_datetime + from .file import File, convert_file_dict_to_httpx_tuples, with_content_type + from .http_client import AsyncHttpClient, HttpClient + from .http_response import AsyncHttpResponse, HttpResponse + from .jsonable_encoder import jsonable_encoder + from .pydantic_utilities import ( + IS_PYDANTIC_V2, + UniversalBaseModel, + UniversalRootModel, + parse_obj_as, + universal_field_validator, + universal_root_validator, + update_forward_refs, + ) + from .query_encoder import encode_query + from .remove_none_from_dict import remove_none_from_dict + from .request_options import RequestOptions + from .serialization import FieldMetadata, convert_and_respect_annotation_metadata +_dynamic_imports: typing.Dict[str, str] = { + "ApiError": ".api_error", + "AsyncClientWrapper": ".client_wrapper", + "AsyncHttpClient": ".http_client", + "AsyncHttpResponse": ".http_response", + "BaseClientWrapper": ".client_wrapper", + "FieldMetadata": ".serialization", + "File": ".file", + "HttpClient": ".http_client", + "HttpResponse": ".http_response", + "IS_PYDANTIC_V2": ".pydantic_utilities", + "RequestOptions": ".request_options", + "SyncClientWrapper": ".client_wrapper", + "UniversalBaseModel": ".pydantic_utilities", + "UniversalRootModel": ".pydantic_utilities", + "convert_and_respect_annotation_metadata": ".serialization", + "convert_file_dict_to_httpx_tuples": ".file", + "encode_query": ".query_encoder", + "jsonable_encoder": ".jsonable_encoder", + "parse_obj_as": ".pydantic_utilities", + "remove_none_from_dict": ".remove_none_from_dict", + "serialize_datetime": ".datetime_utils", + "universal_field_validator": ".pydantic_utilities", + "universal_root_validator": ".pydantic_utilities", + "update_forward_refs": ".pydantic_utilities", + "with_content_type": ".file", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + __all__ = [ "ApiError", "AsyncClientWrapper", "AsyncHttpClient", + "AsyncHttpResponse", "BaseClientWrapper", + "FieldMetadata", "File", "HttpClient", + "HttpResponse", + "IS_PYDANTIC_V2", "RequestOptions", "SyncClientWrapper", + "UniversalBaseModel", + "UniversalRootModel", + "convert_and_respect_annotation_metadata", "convert_file_dict_to_httpx_tuples", - "deep_union_pydantic_dicts", "encode_query", "jsonable_encoder", - "pydantic_v1", + "parse_obj_as", "remove_none_from_dict", "serialize_datetime", + "universal_field_validator", + "universal_root_validator", + "update_forward_refs", + "with_content_type", ] diff --git a/langfuse/api/core/api_error.py b/langfuse/api/core/api_error.py index da734b580..6f850a60c 100644 --- a/langfuse/api/core/api_error.py +++ b/langfuse/api/core/api_error.py @@ -1,17 +1,23 @@ # This file was auto-generated by Fern from our API Definition. -import typing +from typing import Any, Dict, Optional class ApiError(Exception): - status_code: typing.Optional[int] - body: typing.Any + headers: Optional[Dict[str, str]] + status_code: Optional[int] + body: Any def __init__( - self, *, status_code: typing.Optional[int] = None, body: typing.Any = None - ): + self, + *, + headers: Optional[Dict[str, str]] = None, + status_code: Optional[int] = None, + body: Any = None, + ) -> None: + self.headers = headers self.status_code = status_code self.body = body def __str__(self) -> str: - return f"status_code: {self.status_code}, body: {self.body}" + return f"headers: {self.headers}, status_code: {self.status_code}, body: {self.body}" diff --git a/langfuse/api/core/client_wrapper.py b/langfuse/api/core/client_wrapper.py index 8a053f4a7..22bb6a70b 100644 --- a/langfuse/api/core/client_wrapper.py +++ b/langfuse/api/core/client_wrapper.py @@ -3,7 +3,6 @@ import typing import httpx - from .http_client import AsyncHttpClient, HttpClient @@ -16,6 +15,7 @@ def __init__( x_langfuse_public_key: typing.Optional[str] = None, username: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, password: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, base_url: str, timeout: typing.Optional[float] = None, ): @@ -24,11 +24,15 @@ def __init__( self._x_langfuse_public_key = x_langfuse_public_key self._username = username self._password = password + self._headers = headers self._base_url = base_url self._timeout = timeout def get_headers(self) -> typing.Dict[str, str]: - headers: typing.Dict[str, str] = {"X-Fern-Language": "Python"} + headers: typing.Dict[str, str] = { + "X-Fern-Language": "Python", + **(self.get_custom_headers() or {}), + } username = self._get_username() password = self._get_password() if username is not None and password is not None: @@ -53,6 +57,9 @@ def _get_password(self) -> typing.Optional[str]: else: return self._password() + def get_custom_headers(self) -> typing.Optional[typing.Dict[str, str]]: + return self._headers + def get_base_url(self) -> str: return self._base_url @@ -69,6 +76,7 @@ def __init__( x_langfuse_public_key: typing.Optional[str] = None, username: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, password: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, base_url: str, timeout: typing.Optional[float] = None, httpx_client: httpx.Client, @@ -79,14 +87,15 @@ def __init__( x_langfuse_public_key=x_langfuse_public_key, username=username, password=password, + headers=headers, base_url=base_url, timeout=timeout, ) self.httpx_client = HttpClient( httpx_client=httpx_client, - base_headers=self.get_headers(), - base_timeout=self.get_timeout(), - base_url=self.get_base_url(), + base_headers=self.get_headers, + base_timeout=self.get_timeout, + base_url=self.get_base_url, ) @@ -99,8 +108,10 @@ def __init__( x_langfuse_public_key: typing.Optional[str] = None, username: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, password: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None, + headers: typing.Optional[typing.Dict[str, str]] = None, base_url: str, timeout: typing.Optional[float] = None, + async_token: typing.Optional[typing.Callable[[], typing.Awaitable[str]]] = None, httpx_client: httpx.AsyncClient, ): super().__init__( @@ -109,12 +120,22 @@ def __init__( x_langfuse_public_key=x_langfuse_public_key, username=username, password=password, + headers=headers, base_url=base_url, timeout=timeout, ) + self._async_token = async_token self.httpx_client = AsyncHttpClient( httpx_client=httpx_client, - base_headers=self.get_headers(), - base_timeout=self.get_timeout(), - base_url=self.get_base_url(), + base_headers=self.get_headers, + base_timeout=self.get_timeout, + base_url=self.get_base_url, + async_base_headers=self.async_get_headers, ) + + async def async_get_headers(self) -> typing.Dict[str, str]: + headers = self.get_headers() + if self._async_token is not None: + token = await self._async_token() + headers["Authorization"] = f"Bearer {token}" + return headers diff --git a/langfuse/api/core/file.py b/langfuse/api/core/file.py index 6e0f92bfc..3467175cb 100644 --- a/langfuse/api/core/file.py +++ b/langfuse/api/core/file.py @@ -1,30 +1,30 @@ # This file was auto-generated by Fern from our API Definition. -import typing +from typing import IO, Dict, List, Mapping, Optional, Tuple, Union, cast # File typing inspired by the flexibility of types within the httpx library # https://github.com/encode/httpx/blob/master/httpx/_types.py -FileContent = typing.Union[typing.IO[bytes], bytes, str] -File = typing.Union[ +FileContent = Union[IO[bytes], bytes, str] +File = Union[ # file (or bytes) FileContent, # (filename, file (or bytes)) - typing.Tuple[typing.Optional[str], FileContent], + Tuple[Optional[str], FileContent], # (filename, file (or bytes), content_type) - typing.Tuple[typing.Optional[str], FileContent, typing.Optional[str]], + Tuple[Optional[str], FileContent, Optional[str]], # (filename, file (or bytes), content_type, headers) - typing.Tuple[ - typing.Optional[str], + Tuple[ + Optional[str], FileContent, - typing.Optional[str], - typing.Mapping[str, str], + Optional[str], + Mapping[str, str], ], ] def convert_file_dict_to_httpx_tuples( - d: typing.Dict[str, typing.Union[File, typing.List[File]]], -) -> typing.List[typing.Tuple[str, File]]: + d: Dict[str, Union[File, List[File]]], +) -> List[Tuple[str, File]]: """ The format we use is a list of tuples, where the first element is the name of the file and the second is the file object. Typically HTTPX wants @@ -41,3 +41,30 @@ def convert_file_dict_to_httpx_tuples( else: httpx_tuples.append((key, file_like)) return httpx_tuples + + +def with_content_type(*, file: File, default_content_type: str) -> File: + """ + This function resolves to the file's content type, if provided, and defaults + to the default_content_type value if not. + """ + if isinstance(file, tuple): + if len(file) == 2: + filename, content = cast(Tuple[Optional[str], FileContent], file) # type: ignore + return (filename, content, default_content_type) + elif len(file) == 3: + filename, content, file_content_type = cast( + Tuple[Optional[str], FileContent, Optional[str]], file + ) # type: ignore + out_content_type = file_content_type or default_content_type + return (filename, content, out_content_type) + elif len(file) == 4: + filename, content, file_content_type, headers = cast( # type: ignore + Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], + file, + ) + out_content_type = file_content_type or default_content_type + return (filename, content, out_content_type, headers) + else: + raise ValueError(f"Unexpected tuple length: {len(file)}") + return (None, file, default_content_type) diff --git a/langfuse/api/core/force_multipart.py b/langfuse/api/core/force_multipart.py new file mode 100644 index 000000000..5440913fd --- /dev/null +++ b/langfuse/api/core/force_multipart.py @@ -0,0 +1,18 @@ +# This file was auto-generated by Fern from our API Definition. + +from typing import Any, Dict + + +class ForceMultipartDict(Dict[str, Any]): + """ + A dictionary subclass that always evaluates to True in boolean contexts. + + This is used to force multipart/form-data encoding in HTTP requests even when + the dictionary is empty, which would normally evaluate to False. + """ + + def __bool__(self) -> bool: + return True + + +FORCE_MULTIPART = ForceMultipartDict() diff --git a/langfuse/api/core/http_client.py b/langfuse/api/core/http_client.py index 091f71bc1..3025a49ba 100644 --- a/langfuse/api/core/http_client.py +++ b/langfuse/api/core/http_client.py @@ -2,7 +2,6 @@ import asyncio import email.utils -import json import re import time import typing @@ -11,16 +10,17 @@ from random import random import httpx - from .file import File, convert_file_dict_to_httpx_tuples +from .force_multipart import FORCE_MULTIPART from .jsonable_encoder import jsonable_encoder from .query_encoder import encode_query -from .remove_none_from_dict import remove_none_from_dict +from .remove_none_from_dict import remove_none_from_dict as remove_none_from_dict from .request_options import RequestOptions +from httpx._types import RequestFiles -INITIAL_RETRY_DELAY_SECONDS = 0.5 -MAX_RETRY_DELAY_SECONDS = 10 -MAX_RETRY_DELAY_SECONDS_FROM_HEADER = 30 +INITIAL_RETRY_DELAY_SECONDS = 1.0 +MAX_RETRY_DELAY_SECONDS = 60.0 +JITTER_FACTOR = 0.2 # 20% random jitter def _parse_retry_after(response_headers: httpx.Headers) -> typing.Optional[float]: @@ -64,6 +64,38 @@ def _parse_retry_after(response_headers: httpx.Headers) -> typing.Optional[float return seconds +def _add_positive_jitter(delay: float) -> float: + """Add positive jitter (0-20%) to prevent thundering herd.""" + jitter_multiplier = 1 + random() * JITTER_FACTOR + return delay * jitter_multiplier + + +def _add_symmetric_jitter(delay: float) -> float: + """Add symmetric jitter (±10%) for exponential backoff.""" + jitter_multiplier = 1 + (random() - 0.5) * JITTER_FACTOR + return delay * jitter_multiplier + + +def _parse_x_ratelimit_reset(response_headers: httpx.Headers) -> typing.Optional[float]: + """ + Parse the X-RateLimit-Reset header (Unix timestamp in seconds). + Returns seconds to wait, or None if header is missing/invalid. + """ + reset_time_str = response_headers.get("x-ratelimit-reset") + if reset_time_str is None: + return None + + try: + reset_time = int(reset_time_str) + delay = reset_time - time.time() + if delay > 0: + return delay + except (ValueError, TypeError): + pass + + return None + + def _retry_timeout(response: httpx.Response, retries: int) -> float: """ Determine the amount of time to wait before retrying a request. @@ -71,24 +103,45 @@ def _retry_timeout(response: httpx.Response, retries: int) -> float: with a jitter to determine the number of seconds to wait. """ - # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says. + # 1. Check Retry-After header first retry_after = _parse_retry_after(response.headers) - if retry_after is not None and retry_after <= MAX_RETRY_DELAY_SECONDS_FROM_HEADER: - return retry_after + if retry_after is not None and retry_after > 0: + return min(retry_after, MAX_RETRY_DELAY_SECONDS) - # Apply exponential backoff, capped at MAX_RETRY_DELAY_SECONDS. - retry_delay = min( + # 2. Check X-RateLimit-Reset header (with positive jitter) + ratelimit_reset = _parse_x_ratelimit_reset(response.headers) + if ratelimit_reset is not None: + return _add_positive_jitter(min(ratelimit_reset, MAX_RETRY_DELAY_SECONDS)) + + # 3. Fall back to exponential backoff (with symmetric jitter) + backoff = min( INITIAL_RETRY_DELAY_SECONDS * pow(2.0, retries), MAX_RETRY_DELAY_SECONDS ) - - # Add a randomness / jitter to the retry delay to avoid overwhelming the server with retries. - timeout = retry_delay * (1 - 0.25 * random()) - return timeout if timeout >= 0 else 0 + return _add_symmetric_jitter(backoff) def _should_retry(response: httpx.Response) -> bool: - retriable_400s = [429, 408, 409] - return response.status_code >= 500 or response.status_code in retriable_400s + retryable_400s = [429, 408, 409] + return response.status_code >= 500 or response.status_code in retryable_400s + + +def _maybe_filter_none_from_multipart_data( + data: typing.Optional[typing.Any], + request_files: typing.Optional[RequestFiles], + force_multipart: typing.Optional[bool], +) -> typing.Optional[typing.Any]: + """ + Filter None values from data body for multipart/form requests. + This prevents httpx from converting None to empty strings in multipart encoding. + Only applies when files are present or force_multipart is True. + """ + if ( + data is not None + and isinstance(data, typing.Mapping) + and (request_files or force_multipart) + ): + return remove_none_from_dict(data) + return data def remove_omit_from_dict( @@ -147,7 +200,10 @@ def get_request_body( # If both data and json are None, we send json data in the event extra properties are specified json_body = maybe_filter_request_body(json, request_options, omit) - return json_body, data_body + # If you have an empty JSON body, you should just send None + return ( + json_body if json_body != {} else None + ), data_body if data_body != {} else None class HttpClient: @@ -155,9 +211,9 @@ def __init__( self, *, httpx_client: httpx.Client, - base_timeout: typing.Optional[float], - base_headers: typing.Dict[str, str], - base_url: typing.Optional[str] = None, + base_timeout: typing.Callable[[], typing.Optional[float]], + base_headers: typing.Callable[[], typing.Dict[str, str]], + base_url: typing.Optional[typing.Callable[[], str]] = None, ): self.base_url = base_url self.base_timeout = base_timeout @@ -165,7 +221,10 @@ def __init__( self.httpx_client = httpx_client def get_base_url(self, maybe_base_url: typing.Optional[str]) -> str: - base_url = self.base_url if maybe_base_url is None else maybe_base_url + base_url = maybe_base_url + if self.base_url is not None and base_url is None: + base_url = self.base_url() + if base_url is None: raise ValueError( "A base_url is required to make this request, please provide one and try again." @@ -185,32 +244,74 @@ def request( typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]] ] = None, files: typing.Optional[ - typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]] + typing.Union[ + typing.Dict[ + str, typing.Optional[typing.Union[File, typing.List[File]]] + ], + typing.List[typing.Tuple[str, File]], + ] ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + force_multipart: typing.Optional[bool] = None, ) -> httpx.Response: base_url = self.get_base_url(base_url) timeout = ( request_options.get("timeout_in_seconds") if request_options is not None and request_options.get("timeout_in_seconds") is not None - else self.base_timeout + else self.base_timeout() ) json_body, data_body = get_request_body( json=json, data=data, request_options=request_options, omit=omit ) + request_files: typing.Optional[RequestFiles] = ( + convert_file_dict_to_httpx_tuples( + remove_omit_from_dict(remove_none_from_dict(files), omit) + ) + if (files is not None and files is not omit and isinstance(files, dict)) + else None + ) + + if (request_files is None or len(request_files) == 0) and force_multipart: + request_files = FORCE_MULTIPART + + data_body = _maybe_filter_none_from_multipart_data( + data_body, request_files, force_multipart + ) + + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( + remove_none_from_dict( + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) + or {} + if request_options is not None + else {} + ), + }, + omit, + ) + ) + ) + ) + response = self.httpx_client.request( method=method, url=urllib.parse.urljoin(f"{base_url}/", path), headers=jsonable_encoder( remove_none_from_dict( { - **self.base_headers, + **self.base_headers(), **(headers if headers is not None else {}), **( request_options.get("additional_headers", {}) or {} @@ -220,40 +321,19 @@ def request( } ) ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get( - "additional_query_parameters", {} - ) - or {} - if request_options is not None - else {} - ), - }, - omit, - ) - ) - ) - ), + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, - files=convert_file_dict_to_httpx_tuples(remove_none_from_dict(files)) - if files is not None - else None, + files=request_files, timeout=timeout, ) max_retries: int = ( - request_options.get("max_retries", 0) if request_options is not None else 0 + request_options.get("max_retries", 2) if request_options is not None else 2 ) if _should_retry(response=response): - if max_retries > retries: + if retries < max_retries: time.sleep(_retry_timeout(response=response, retries=retries)) return self.request( path=path, @@ -285,32 +365,73 @@ def stream( typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]] ] = None, files: typing.Optional[ - typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]] + typing.Union[ + typing.Dict[ + str, typing.Optional[typing.Union[File, typing.List[File]]] + ], + typing.List[typing.Tuple[str, File]], + ] ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + force_multipart: typing.Optional[bool] = None, ) -> typing.Iterator[httpx.Response]: base_url = self.get_base_url(base_url) timeout = ( request_options.get("timeout_in_seconds") if request_options is not None and request_options.get("timeout_in_seconds") is not None - else self.base_timeout + else self.base_timeout() ) + request_files: typing.Optional[RequestFiles] = ( + convert_file_dict_to_httpx_tuples( + remove_omit_from_dict(remove_none_from_dict(files), omit) + ) + if (files is not None and files is not omit and isinstance(files, dict)) + else None + ) + + if (request_files is None or len(request_files) == 0) and force_multipart: + request_files = FORCE_MULTIPART + json_body, data_body = get_request_body( json=json, data=data, request_options=request_options, omit=omit ) + data_body = _maybe_filter_none_from_multipart_data( + data_body, request_files, force_multipart + ) + + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( + remove_none_from_dict( + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) + if request_options is not None + else {} + ), + }, + omit, + ) + ) + ) + ) + with self.httpx_client.stream( method=method, url=urllib.parse.urljoin(f"{base_url}/", path), headers=jsonable_encoder( remove_none_from_dict( { - **self.base_headers, + **self.base_headers(), **(headers if headers is not None else {}), **( request_options.get("additional_headers", {}) @@ -320,31 +441,11 @@ def stream( } ) ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get( - "additional_query_parameters", {} - ) - if request_options is not None - else {} - ), - }, - omit, - ) - ) - ) - ), + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, - files=convert_file_dict_to_httpx_tuples(remove_none_from_dict(files)) - if files is not None - else None, + files=request_files, timeout=timeout, ) as stream: yield stream @@ -355,17 +456,29 @@ def __init__( self, *, httpx_client: httpx.AsyncClient, - base_timeout: typing.Optional[float], - base_headers: typing.Dict[str, str], - base_url: typing.Optional[str] = None, + base_timeout: typing.Callable[[], typing.Optional[float]], + base_headers: typing.Callable[[], typing.Dict[str, str]], + base_url: typing.Optional[typing.Callable[[], str]] = None, + async_base_headers: typing.Optional[ + typing.Callable[[], typing.Awaitable[typing.Dict[str, str]]] + ] = None, ): self.base_url = base_url self.base_timeout = base_timeout self.base_headers = base_headers + self.async_base_headers = async_base_headers self.httpx_client = httpx_client + async def _get_headers(self) -> typing.Dict[str, str]: + if self.async_base_headers is not None: + return await self.async_base_headers() + return self.base_headers() + def get_base_url(self, maybe_base_url: typing.Optional[str]) -> str: - base_url = self.base_url if maybe_base_url is None else maybe_base_url + base_url = maybe_base_url + if self.base_url is not None and base_url is None: + base_url = self.base_url() + if base_url is None: raise ValueError( "A base_url is required to make this request, please provide one and try again." @@ -385,25 +498,70 @@ async def request( typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]] ] = None, files: typing.Optional[ - typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]] + typing.Union[ + typing.Dict[ + str, typing.Optional[typing.Union[File, typing.List[File]]] + ], + typing.List[typing.Tuple[str, File]], + ] ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + force_multipart: typing.Optional[bool] = None, ) -> httpx.Response: base_url = self.get_base_url(base_url) timeout = ( request_options.get("timeout_in_seconds") if request_options is not None and request_options.get("timeout_in_seconds") is not None - else self.base_timeout + else self.base_timeout() ) + request_files: typing.Optional[RequestFiles] = ( + convert_file_dict_to_httpx_tuples( + remove_omit_from_dict(remove_none_from_dict(files), omit) + ) + if (files is not None and files is not omit and isinstance(files, dict)) + else None + ) + + if (request_files is None or len(request_files) == 0) and force_multipart: + request_files = FORCE_MULTIPART + json_body, data_body = get_request_body( json=json, data=data, request_options=request_options, omit=omit ) + data_body = _maybe_filter_none_from_multipart_data( + data_body, request_files, force_multipart + ) + + # Get headers (supports async token providers) + _headers = await self._get_headers() + + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( + remove_none_from_dict( + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) + or {} + if request_options is not None + else {} + ), + }, + omit, + ) + ) + ) + ) + # Add the input to each of these and do None-safety checks response = await self.httpx_client.request( method=method, @@ -411,7 +569,7 @@ async def request( headers=jsonable_encoder( remove_none_from_dict( { - **self.base_headers, + **_headers, **(headers if headers is not None else {}), **( request_options.get("additional_headers", {}) or {} @@ -421,40 +579,19 @@ async def request( } ) ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get( - "additional_query_parameters", {} - ) - or {} - if request_options is not None - else {} - ), - }, - omit, - ) - ) - ) - ), + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, - files=convert_file_dict_to_httpx_tuples(remove_none_from_dict(files)) - if files is not None - else None, + files=request_files, timeout=timeout, ) max_retries: int = ( - request_options.get("max_retries", 0) if request_options is not None else 0 + request_options.get("max_retries", 2) if request_options is not None else 2 ) if _should_retry(response=response): - if max_retries > retries: + if retries < max_retries: await asyncio.sleep(_retry_timeout(response=response, retries=retries)) return await self.request( path=path, @@ -485,32 +622,76 @@ async def stream( typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]] ] = None, files: typing.Optional[ - typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]] + typing.Union[ + typing.Dict[ + str, typing.Optional[typing.Union[File, typing.List[File]]] + ], + typing.List[typing.Tuple[str, File]], + ] ] = None, headers: typing.Optional[typing.Dict[str, typing.Any]] = None, request_options: typing.Optional[RequestOptions] = None, retries: int = 0, omit: typing.Optional[typing.Any] = None, + force_multipart: typing.Optional[bool] = None, ) -> typing.AsyncIterator[httpx.Response]: base_url = self.get_base_url(base_url) timeout = ( request_options.get("timeout_in_seconds") if request_options is not None and request_options.get("timeout_in_seconds") is not None - else self.base_timeout + else self.base_timeout() ) + request_files: typing.Optional[RequestFiles] = ( + convert_file_dict_to_httpx_tuples( + remove_omit_from_dict(remove_none_from_dict(files), omit) + ) + if (files is not None and files is not omit and isinstance(files, dict)) + else None + ) + + if (request_files is None or len(request_files) == 0) and force_multipart: + request_files = FORCE_MULTIPART + json_body, data_body = get_request_body( json=json, data=data, request_options=request_options, omit=omit ) + data_body = _maybe_filter_none_from_multipart_data( + data_body, request_files, force_multipart + ) + + # Get headers (supports async token providers) + _headers = await self._get_headers() + + # Compute encoded params separately to avoid passing empty list to httpx + # (httpx strips existing query params from URL when params=[] is passed) + _encoded_params = encode_query( + jsonable_encoder( + remove_none_from_dict( + remove_omit_from_dict( + { + **(params if params is not None else {}), + **( + request_options.get("additional_query_parameters", {}) + if request_options is not None + else {} + ), + }, + omit=omit, + ) + ) + ) + ) + async with self.httpx_client.stream( method=method, url=urllib.parse.urljoin(f"{base_url}/", path), headers=jsonable_encoder( remove_none_from_dict( { - **self.base_headers, + **_headers, **(headers if headers is not None else {}), **( request_options.get("additional_headers", {}) @@ -520,31 +701,11 @@ async def stream( } ) ), - params=encode_query( - jsonable_encoder( - remove_none_from_dict( - remove_omit_from_dict( - { - **(params if params is not None else {}), - **( - request_options.get( - "additional_query_parameters", {} - ) - if request_options is not None - else {} - ), - }, - omit=omit, - ) - ) - ) - ), + params=_encoded_params if _encoded_params else None, json=json_body, data=data_body, content=content, - files=convert_file_dict_to_httpx_tuples(remove_none_from_dict(files)) - if files is not None - else None, + files=request_files, timeout=timeout, ) as stream: yield stream diff --git a/langfuse/api/core/http_response.py b/langfuse/api/core/http_response.py new file mode 100644 index 000000000..2479747e8 --- /dev/null +++ b/langfuse/api/core/http_response.py @@ -0,0 +1,55 @@ +# This file was auto-generated by Fern from our API Definition. + +from typing import Dict, Generic, TypeVar + +import httpx + +# Generic to represent the underlying type of the data wrapped by the HTTP response. +T = TypeVar("T") + + +class BaseHttpResponse: + """Minimalist HTTP response wrapper that exposes response headers.""" + + _response: httpx.Response + + def __init__(self, response: httpx.Response): + self._response = response + + @property + def headers(self) -> Dict[str, str]: + return dict(self._response.headers) + + +class HttpResponse(Generic[T], BaseHttpResponse): + """HTTP response wrapper that exposes response headers and data.""" + + _data: T + + def __init__(self, response: httpx.Response, data: T): + super().__init__(response) + self._data = data + + @property + def data(self) -> T: + return self._data + + def close(self) -> None: + self._response.close() + + +class AsyncHttpResponse(Generic[T], BaseHttpResponse): + """HTTP response wrapper that exposes response headers and data.""" + + _data: T + + def __init__(self, response: httpx.Response, data: T): + super().__init__(response) + self._data = data + + @property + def data(self) -> T: + return self._data + + async def close(self) -> None: + await self._response.aclose() diff --git a/langfuse/api/core/http_sse/__init__.py b/langfuse/api/core/http_sse/__init__.py new file mode 100644 index 000000000..ab0b4995a --- /dev/null +++ b/langfuse/api/core/http_sse/__init__.py @@ -0,0 +1,48 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from ._api import EventSource, aconnect_sse, connect_sse + from ._exceptions import SSEError + from ._models import ServerSentEvent +_dynamic_imports: typing.Dict[str, str] = { + "EventSource": "._api", + "SSEError": "._exceptions", + "ServerSentEvent": "._models", + "aconnect_sse": "._api", + "connect_sse": "._api", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["EventSource", "SSEError", "ServerSentEvent", "aconnect_sse", "connect_sse"] diff --git a/langfuse/api/core/http_sse/_api.py b/langfuse/api/core/http_sse/_api.py new file mode 100644 index 000000000..eb739a22b --- /dev/null +++ b/langfuse/api/core/http_sse/_api.py @@ -0,0 +1,114 @@ +# This file was auto-generated by Fern from our API Definition. + +import re +from contextlib import asynccontextmanager, contextmanager +from typing import Any, AsyncGenerator, AsyncIterator, Iterator, cast + +import httpx +from ._decoders import SSEDecoder +from ._exceptions import SSEError +from ._models import ServerSentEvent + + +class EventSource: + def __init__(self, response: httpx.Response) -> None: + self._response = response + + def _check_content_type(self) -> None: + content_type = self._response.headers.get("content-type", "").partition(";")[0] + if "text/event-stream" not in content_type: + raise SSEError( + f"Expected response header Content-Type to contain 'text/event-stream', got {content_type!r}" + ) + + def _get_charset(self) -> str: + """Extract charset from Content-Type header, fallback to UTF-8.""" + content_type = self._response.headers.get("content-type", "") + + # Parse charset parameter using regex + charset_match = re.search(r"charset=([^;\s]+)", content_type, re.IGNORECASE) + if charset_match: + charset = charset_match.group(1).strip("\"'") + # Validate that it's a known encoding + try: + # Test if the charset is valid by trying to encode/decode + "test".encode(charset).decode(charset) + return charset + except (LookupError, UnicodeError): + # If charset is invalid, fall back to UTF-8 + pass + + # Default to UTF-8 if no charset specified or invalid charset + return "utf-8" + + @property + def response(self) -> httpx.Response: + return self._response + + def iter_sse(self) -> Iterator[ServerSentEvent]: + self._check_content_type() + decoder = SSEDecoder() + charset = self._get_charset() + + buffer = "" + for chunk in self._response.iter_bytes(): + # Decode chunk using detected charset + text_chunk = chunk.decode(charset, errors="replace") + buffer += text_chunk + + # Process complete lines + while "\n" in buffer: + line, buffer = buffer.split("\n", 1) + line = line.rstrip("\r") + sse = decoder.decode(line) + # when we reach a "\n\n" => line = '' + # => decoder will attempt to return an SSE Event + if sse is not None: + yield sse + + # Process any remaining data in buffer + if buffer.strip(): + line = buffer.rstrip("\r") + sse = decoder.decode(line) + if sse is not None: + yield sse + + async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]: + self._check_content_type() + decoder = SSEDecoder() + lines = cast(AsyncGenerator[str, None], self._response.aiter_lines()) + try: + async for line in lines: + line = line.rstrip("\n") + sse = decoder.decode(line) + if sse is not None: + yield sse + finally: + await lines.aclose() + + +@contextmanager +def connect_sse( + client: httpx.Client, method: str, url: str, **kwargs: Any +) -> Iterator[EventSource]: + headers = kwargs.pop("headers", {}) + headers["Accept"] = "text/event-stream" + headers["Cache-Control"] = "no-store" + + with client.stream(method, url, headers=headers, **kwargs) as response: + yield EventSource(response) + + +@asynccontextmanager +async def aconnect_sse( + client: httpx.AsyncClient, + method: str, + url: str, + **kwargs: Any, +) -> AsyncIterator[EventSource]: + headers = kwargs.pop("headers", {}) + headers["Accept"] = "text/event-stream" + headers["Cache-Control"] = "no-store" + + async with client.stream(method, url, headers=headers, **kwargs) as response: + yield EventSource(response) diff --git a/langfuse/api/core/http_sse/_decoders.py b/langfuse/api/core/http_sse/_decoders.py new file mode 100644 index 000000000..bdec57b44 --- /dev/null +++ b/langfuse/api/core/http_sse/_decoders.py @@ -0,0 +1,66 @@ +# This file was auto-generated by Fern from our API Definition. + +from typing import List, Optional + +from ._models import ServerSentEvent + + +class SSEDecoder: + def __init__(self) -> None: + self._event = "" + self._data: List[str] = [] + self._last_event_id = "" + self._retry: Optional[int] = None + + def decode(self, line: str) -> Optional[ServerSentEvent]: + # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 + + if not line: + if ( + not self._event + and not self._data + and not self._last_event_id + and self._retry is None + ): + return None + + sse = ServerSentEvent( + event=self._event, + data="\n".join(self._data), + id=self._last_event_id, + retry=self._retry, + ) + + # NOTE: as per the SSE spec, do not reset last_event_id. + self._event = "" + self._data = [] + self._retry = None + + return sse + + if line.startswith(":"): + return None + + fieldname, _, value = line.partition(":") + + if value.startswith(" "): + value = value[1:] + + if fieldname == "event": + self._event = value + elif fieldname == "data": + self._data.append(value) + elif fieldname == "id": + if "\0" in value: + pass + else: + self._last_event_id = value + elif fieldname == "retry": + try: + self._retry = int(value) + except (TypeError, ValueError): + pass + else: + pass # Field is ignored. + + return None diff --git a/langfuse/api/resources/utils/resources/pagination/__init__.py b/langfuse/api/core/http_sse/_exceptions.py similarity index 51% rename from langfuse/api/resources/utils/resources/pagination/__init__.py rename to langfuse/api/core/http_sse/_exceptions.py index 9bd1e5f71..81605a8a6 100644 --- a/langfuse/api/resources/utils/resources/pagination/__init__.py +++ b/langfuse/api/core/http_sse/_exceptions.py @@ -1,5 +1,7 @@ # This file was auto-generated by Fern from our API Definition. -from .types import MetaResponse +import httpx -__all__ = ["MetaResponse"] + +class SSEError(httpx.TransportError): + pass diff --git a/langfuse/api/core/http_sse/_models.py b/langfuse/api/core/http_sse/_models.py new file mode 100644 index 000000000..1af57f8fd --- /dev/null +++ b/langfuse/api/core/http_sse/_models.py @@ -0,0 +1,17 @@ +# This file was auto-generated by Fern from our API Definition. + +import json +from dataclasses import dataclass +from typing import Any, Optional + + +@dataclass(frozen=True) +class ServerSentEvent: + event: str = "message" + data: str = "" + id: str = "" + retry: Optional[int] = None + + def json(self) -> Any: + """Parse the data field as JSON.""" + return json.loads(self.data) diff --git a/langfuse/api/core/jsonable_encoder.py b/langfuse/api/core/jsonable_encoder.py index 7a05e9190..90f53dfa7 100644 --- a/langfuse/api/core/jsonable_encoder.py +++ b/langfuse/api/core/jsonable_encoder.py @@ -11,35 +11,23 @@ import base64 import dataclasses import datetime as dt -from collections import defaultdict from enum import Enum from pathlib import PurePath from types import GeneratorType -from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union +from typing import Any, Callable, Dict, List, Optional, Set, Union +import pydantic from .datetime_utils import serialize_datetime -from .pydantic_utilities import pydantic_v1 +from .pydantic_utilities import ( + IS_PYDANTIC_V2, + encode_by_type, + to_jsonable_with_fallback, +) SetIntStr = Set[Union[int, str]] DictIntStrAny = Dict[Union[int, str], Any] -def generate_encoders_by_class_tuples( - type_encoder_map: Dict[Any, Callable[[Any], Any]], -) -> Dict[Callable[[Any], Any], Tuple[Any, ...]]: - encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict( - tuple - ) - for type_, encoder in type_encoder_map.items(): - encoders_by_class_tuples[encoder] += (type_,) - return encoders_by_class_tuples - - -encoders_by_class_tuples = generate_encoders_by_class_tuples( - pydantic_v1.json.ENCODERS_BY_TYPE -) - - def jsonable_encoder( obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None ) -> Any: @@ -51,16 +39,21 @@ def jsonable_encoder( for encoder_type, encoder_instance in custom_encoder.items(): if isinstance(obj, encoder_type): return encoder_instance(obj) - if isinstance(obj, pydantic_v1.BaseModel): - encoder = getattr(obj.__config__, "json_encoders", {}) + if isinstance(obj, pydantic.BaseModel): + if IS_PYDANTIC_V2: + encoder = getattr(obj.model_config, "json_encoders", {}) # type: ignore # Pydantic v2 + else: + encoder = getattr(obj.__config__, "json_encoders", {}) # type: ignore # Pydantic v1 if custom_encoder: encoder.update(custom_encoder) obj_dict = obj.dict(by_alias=True) if "__root__" in obj_dict: obj_dict = obj_dict["__root__"] + if "root" in obj_dict: + obj_dict = obj_dict["root"] return jsonable_encoder(obj_dict, custom_encoder=encoder) if dataclasses.is_dataclass(obj): - obj_dict = dataclasses.asdict(obj) + obj_dict = dataclasses.asdict(obj) # type: ignore return jsonable_encoder(obj_dict, custom_encoder=custom_encoder) if isinstance(obj, bytes): return base64.b64encode(obj).decode("utf-8") @@ -89,20 +82,21 @@ def jsonable_encoder( encoded_list.append(jsonable_encoder(item, custom_encoder=custom_encoder)) return encoded_list - if type(obj) in pydantic_v1.json.ENCODERS_BY_TYPE: - return pydantic_v1.json.ENCODERS_BY_TYPE[type(obj)](obj) - for encoder, classes_tuple in encoders_by_class_tuples.items(): - if isinstance(obj, classes_tuple): - return encoder(obj) + def fallback_serializer(o: Any) -> Any: + attempt_encode = encode_by_type(o) + if attempt_encode is not None: + return attempt_encode - try: - data = dict(obj) - except Exception as e: - errors: List[Exception] = [] - errors.append(e) try: - data = vars(obj) + data = dict(o) except Exception as e: + errors: List[Exception] = [] errors.append(e) - raise ValueError(errors) from e - return jsonable_encoder(data, custom_encoder=custom_encoder) + try: + data = vars(o) + except Exception as e: + errors.append(e) + raise ValueError(errors) from e + return jsonable_encoder(data, custom_encoder=custom_encoder) + + return to_jsonable_with_fallback(obj, fallback_serializer) diff --git a/langfuse/api/core/pydantic_utilities.py b/langfuse/api/core/pydantic_utilities.py index a72c1a52f..d2b7b51b6 100644 --- a/langfuse/api/core/pydantic_utilities.py +++ b/langfuse/api/core/pydantic_utilities.py @@ -1,28 +1,310 @@ # This file was auto-generated by Fern from our API Definition. -import typing +# nopycln: file +import datetime as dt +from collections import defaultdict +from typing import ( + Any, + Callable, + ClassVar, + Dict, + List, + Mapping, + Optional, + Set, + Tuple, + Type, + TypeVar, + Union, + cast, +) import pydantic IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.") if IS_PYDANTIC_V2: - import pydantic.v1 as pydantic_v1 # type: ignore # nopycln: import + from pydantic.v1.datetime_parse import parse_date as parse_date + from pydantic.v1.datetime_parse import parse_datetime as parse_datetime + from pydantic.v1.fields import ModelField as ModelField + from pydantic.v1.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[attr-defined] + from pydantic.v1.typing import get_args as get_args + from pydantic.v1.typing import get_origin as get_origin + from pydantic.v1.typing import is_literal_type as is_literal_type + from pydantic.v1.typing import is_union as is_union else: - import pydantic as pydantic_v1 # type: ignore # nopycln: import + from pydantic.datetime_parse import parse_date as parse_date # type: ignore[no-redef] + from pydantic.datetime_parse import parse_datetime as parse_datetime # type: ignore[no-redef] + from pydantic.fields import ModelField as ModelField # type: ignore[attr-defined, no-redef] + from pydantic.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[no-redef] + from pydantic.typing import get_args as get_args # type: ignore[no-redef] + from pydantic.typing import get_origin as get_origin # type: ignore[no-redef] + from pydantic.typing import is_literal_type as is_literal_type # type: ignore[no-redef] + from pydantic.typing import is_union as is_union # type: ignore[no-redef] + +from .datetime_utils import serialize_datetime +from .serialization import convert_and_respect_annotation_metadata +from typing_extensions import TypeAlias + +T = TypeVar("T") +Model = TypeVar("Model", bound=pydantic.BaseModel) + + +def parse_obj_as(type_: Type[T], object_: Any) -> T: + dealiased_object = convert_and_respect_annotation_metadata( + object_=object_, annotation=type_, direction="read" + ) + if IS_PYDANTIC_V2: + adapter = pydantic.TypeAdapter(type_) # type: ignore[attr-defined] + return adapter.validate_python(dealiased_object) + return pydantic.parse_obj_as(type_, dealiased_object) + + +def to_jsonable_with_fallback( + obj: Any, fallback_serializer: Callable[[Any], Any] +) -> Any: + if IS_PYDANTIC_V2: + from pydantic_core import to_jsonable_python + + return to_jsonable_python(obj, fallback=fallback_serializer) + return fallback_serializer(obj) + + +class UniversalBaseModel(pydantic.BaseModel): + if IS_PYDANTIC_V2: + model_config: ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( # type: ignore[typeddict-unknown-key] + # Allow fields beginning with `model_` to be used in the model + protected_namespaces=(), + ) + + @pydantic.model_serializer(mode="plain", when_used="json") # type: ignore[attr-defined] + def serialize_model(self) -> Any: # type: ignore[name-defined] + serialized = self.dict() # type: ignore[attr-defined] + data = { + k: serialize_datetime(v) if isinstance(v, dt.datetime) else v + for k, v in serialized.items() + } + return data + + else: + + class Config: + smart_union = True + json_encoders = {dt.datetime: serialize_datetime} + + @classmethod + def model_construct( + cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any + ) -> "Model": + dealiased_object = convert_and_respect_annotation_metadata( + object_=values, annotation=cls, direction="read" + ) + return cls.construct(_fields_set, **dealiased_object) + + @classmethod + def construct( + cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any + ) -> "Model": + dealiased_object = convert_and_respect_annotation_metadata( + object_=values, annotation=cls, direction="read" + ) + if IS_PYDANTIC_V2: + return super().model_construct(_fields_set, **dealiased_object) # type: ignore[misc] + return super().construct(_fields_set, **dealiased_object) + + def json(self, **kwargs: Any) -> str: + kwargs_with_defaults = { + "by_alias": True, + "exclude_unset": True, + **kwargs, + } + if IS_PYDANTIC_V2: + return super().model_dump_json(**kwargs_with_defaults) # type: ignore[misc] + return super().json(**kwargs_with_defaults) + + def dict(self, **kwargs: Any) -> Dict[str, Any]: + """ + Override the default dict method to `exclude_unset` by default. This function patches + `exclude_unset` to work include fields within non-None default values. + """ + # Note: the logic here is multiplexed given the levers exposed in Pydantic V1 vs V2 + # Pydantic V1's .dict can be extremely slow, so we do not want to call it twice. + # + # We'd ideally do the same for Pydantic V2, but it shells out to a library to serialize models + # that we have less control over, and this is less intrusive than custom serializers for now. + if IS_PYDANTIC_V2: + kwargs_with_defaults_exclude_unset = { + **kwargs, + "by_alias": True, + "exclude_unset": True, + "exclude_none": False, + } + kwargs_with_defaults_exclude_none = { + **kwargs, + "by_alias": True, + "exclude_none": True, + "exclude_unset": False, + } + dict_dump = deep_union_pydantic_dicts( + super().model_dump(**kwargs_with_defaults_exclude_unset), # type: ignore[misc] + super().model_dump(**kwargs_with_defaults_exclude_none), # type: ignore[misc] + ) + + else: + _fields_set = self.__fields_set__.copy() + + fields = _get_model_fields(self.__class__) + for name, field in fields.items(): + if name not in _fields_set: + default = _get_field_default(field) + + # If the default values are non-null act like they've been set + # This effectively allows exclude_unset to work like exclude_none where + # the latter passes through intentionally set none values. + if default is not None or ( + "exclude_unset" in kwargs and not kwargs["exclude_unset"] + ): + _fields_set.add(name) + + if default is not None: + self.__fields_set__.add(name) + + kwargs_with_defaults_exclude_unset_include_fields = { + "by_alias": True, + "exclude_unset": True, + "include": _fields_set, + **kwargs, + } + + dict_dump = super().dict( + **kwargs_with_defaults_exclude_unset_include_fields + ) + + return cast( + Dict[str, Any], + convert_and_respect_annotation_metadata( + object_=dict_dump, annotation=self.__class__, direction="write" + ), + ) + + +def _union_list_of_pydantic_dicts( + source: List[Any], destination: List[Any] +) -> List[Any]: + converted_list: List[Any] = [] + for i, item in enumerate(source): + destination_value = destination[i] + if isinstance(item, dict): + converted_list.append(deep_union_pydantic_dicts(item, destination_value)) + elif isinstance(item, list): + converted_list.append( + _union_list_of_pydantic_dicts(item, destination_value) + ) + else: + converted_list.append(item) + return converted_list def deep_union_pydantic_dicts( - source: typing.Dict[str, typing.Any], destination: typing.Dict[str, typing.Any] -) -> typing.Dict[str, typing.Any]: + source: Dict[str, Any], destination: Dict[str, Any] +) -> Dict[str, Any]: for key, value in source.items(): + node = destination.setdefault(key, {}) if isinstance(value, dict): - node = destination.setdefault(key, {}) deep_union_pydantic_dicts(value, node) + # Note: we do not do this same processing for sets given we do not have sets of models + # and given the sets are unordered, the processing of the set and matching objects would + # be non-trivial. + elif isinstance(value, list): + destination[key] = _union_list_of_pydantic_dicts(value, node) else: destination[key] = value return destination -__all__ = ["pydantic_v1"] +if IS_PYDANTIC_V2: + + class V2RootModel(UniversalBaseModel, pydantic.RootModel): # type: ignore[misc, name-defined, type-arg] + pass + + UniversalRootModel: TypeAlias = V2RootModel # type: ignore[misc] +else: + UniversalRootModel: TypeAlias = UniversalBaseModel # type: ignore[misc, no-redef] + + +def encode_by_type(o: Any) -> Any: + encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict( + tuple + ) + for type_, encoder in encoders_by_type.items(): + encoders_by_class_tuples[encoder] += (type_,) + + if type(o) in encoders_by_type: + return encoders_by_type[type(o)](o) + for encoder, classes_tuple in encoders_by_class_tuples.items(): + if isinstance(o, classes_tuple): + return encoder(o) + + +def update_forward_refs(model: Type["Model"], **localns: Any) -> None: + if IS_PYDANTIC_V2: + model.model_rebuild(raise_errors=False) # type: ignore[attr-defined] + else: + model.update_forward_refs(**localns) + + +# Mirrors Pydantic's internal typing +AnyCallable = Callable[..., Any] + + +def universal_root_validator( + pre: bool = False, +) -> Callable[[AnyCallable], AnyCallable]: + def decorator(func: AnyCallable) -> AnyCallable: + if IS_PYDANTIC_V2: + # In Pydantic v2, for RootModel we always use "before" mode + # The custom validators transform the input value before the model is created + return cast(AnyCallable, pydantic.model_validator(mode="before")(func)) # type: ignore[attr-defined] + return cast(AnyCallable, pydantic.root_validator(pre=pre)(func)) # type: ignore[call-overload] + + return decorator + + +def universal_field_validator( + field_name: str, pre: bool = False +) -> Callable[[AnyCallable], AnyCallable]: + def decorator(func: AnyCallable) -> AnyCallable: + if IS_PYDANTIC_V2: + return cast( + AnyCallable, + pydantic.field_validator(field_name, mode="before" if pre else "after")( + func + ), + ) # type: ignore[attr-defined] + return cast(AnyCallable, pydantic.validator(field_name, pre=pre)(func)) + + return decorator + + +PydanticField = Union[ModelField, pydantic.fields.FieldInfo] + + +def _get_model_fields(model: Type["Model"]) -> Mapping[str, PydanticField]: + if IS_PYDANTIC_V2: + return cast(Mapping[str, PydanticField], model.model_fields) # type: ignore[attr-defined] + return cast(Mapping[str, PydanticField], model.__fields__) + + +def _get_field_default(field: PydanticField) -> Any: + try: + value = field.get_default() # type: ignore[union-attr] + except: + value = field.default + if IS_PYDANTIC_V2: + from pydantic_core import PydanticUndefined + + if value == PydanticUndefined: + return None + return value + return value diff --git a/langfuse/api/core/query_encoder.py b/langfuse/api/core/query_encoder.py index 069633086..03fbf59bd 100644 --- a/langfuse/api/core/query_encoder.py +++ b/langfuse/api/core/query_encoder.py @@ -1,39 +1,60 @@ # This file was auto-generated by Fern from our API Definition. -from collections import ChainMap -from typing import Any, Dict, Optional +from typing import Any, Dict, List, Optional, Tuple -from .pydantic_utilities import pydantic_v1 +import pydantic # Flattens dicts to be of the form {"key[subkey][subkey2]": value} where value is not a dict def traverse_query_dict( dict_flat: Dict[str, Any], key_prefix: Optional[str] = None -) -> Dict[str, Any]: - result = {} +) -> List[Tuple[str, Any]]: + result = [] for k, v in dict_flat.items(): key = f"{key_prefix}[{k}]" if key_prefix is not None else k if isinstance(v, dict): - result.update(traverse_query_dict(v, key)) + result.extend(traverse_query_dict(v, key)) + elif isinstance(v, list): + for arr_v in v: + if isinstance(arr_v, dict): + result.extend(traverse_query_dict(arr_v, key)) + else: + result.append((key, arr_v)) else: - result[key] = v + result.append((key, v)) return result -def single_query_encoder(query_key: str, query_value: Any) -> Dict[str, Any]: - if isinstance(query_value, pydantic_v1.BaseModel) or isinstance(query_value, dict): - if isinstance(query_value, pydantic_v1.BaseModel): +def single_query_encoder(query_key: str, query_value: Any) -> List[Tuple[str, Any]]: + if isinstance(query_value, pydantic.BaseModel) or isinstance(query_value, dict): + if isinstance(query_value, pydantic.BaseModel): obj_dict = query_value.dict(by_alias=True) else: obj_dict = query_value return traverse_query_dict(obj_dict, query_key) + elif isinstance(query_value, list): + encoded_values: List[Tuple[str, Any]] = [] + for value in query_value: + if isinstance(value, pydantic.BaseModel) or isinstance(value, dict): + if isinstance(value, pydantic.BaseModel): + obj_dict = value.dict(by_alias=True) + elif isinstance(value, dict): + obj_dict = value - return {query_key: query_value} + encoded_values.extend(single_query_encoder(query_key, obj_dict)) + else: + encoded_values.append((query_key, value)) + return encoded_values -def encode_query(query: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]: - return ( - dict(ChainMap(*[single_query_encoder(k, v) for k, v in query.items()])) - if query is not None - else None - ) + return [(query_key, query_value)] + + +def encode_query(query: Optional[Dict[str, Any]]) -> Optional[List[Tuple[str, Any]]]: + if query is None: + return None + + encoded_query = [] + for k, v in query.items(): + encoded_query.extend(single_query_encoder(k, v)) + return encoded_query diff --git a/langfuse/api/core/request_options.py b/langfuse/api/core/request_options.py index d0bf0dbce..1b3880443 100644 --- a/langfuse/api/core/request_options.py +++ b/langfuse/api/core/request_options.py @@ -23,6 +23,8 @@ class RequestOptions(typing.TypedDict, total=False): - additional_query_parameters: typing.Dict[str, typing.Any]. A dictionary containing additional parameters to spread into the request's query parameters dict - additional_body_parameters: typing.Dict[str, typing.Any]. A dictionary containing additional parameters to spread into the request's body parameters dict + + - chunk_size: int. The size, in bytes, to process each chunk of data being streamed back within the response. This equates to leveraging `chunk_size` within `requests` or `httpx`, and is only leveraged for file downloads. """ timeout_in_seconds: NotRequired[int] @@ -30,3 +32,4 @@ class RequestOptions(typing.TypedDict, total=False): additional_headers: NotRequired[typing.Dict[str, typing.Any]] additional_query_parameters: NotRequired[typing.Dict[str, typing.Any]] additional_body_parameters: NotRequired[typing.Dict[str, typing.Any]] + chunk_size: NotRequired[int] diff --git a/langfuse/api/core/serialization.py b/langfuse/api/core/serialization.py new file mode 100644 index 000000000..ad6eb8d7f --- /dev/null +++ b/langfuse/api/core/serialization.py @@ -0,0 +1,282 @@ +# This file was auto-generated by Fern from our API Definition. + +import collections +import inspect +import typing + +import pydantic +import typing_extensions + + +class FieldMetadata: + """ + Metadata class used to annotate fields to provide additional information. + + Example: + class MyDict(TypedDict): + field: typing.Annotated[str, FieldMetadata(alias="field_name")] + + Will serialize: `{"field": "value"}` + To: `{"field_name": "value"}` + """ + + alias: str + + def __init__(self, *, alias: str) -> None: + self.alias = alias + + +def convert_and_respect_annotation_metadata( + *, + object_: typing.Any, + annotation: typing.Any, + inner_type: typing.Optional[typing.Any] = None, + direction: typing.Literal["read", "write"], +) -> typing.Any: + """ + Respect the metadata annotations on a field, such as aliasing. This function effectively + manipulates the dict-form of an object to respect the metadata annotations. This is primarily used for + TypedDicts, which cannot support aliasing out of the box, and can be extended for additional + utilities, such as defaults. + + Parameters + ---------- + object_ : typing.Any + + annotation : type + The type we're looking to apply typing annotations from + + inner_type : typing.Optional[type] + + Returns + ------- + typing.Any + """ + + if object_ is None: + return None + if inner_type is None: + inner_type = annotation + + clean_type = _remove_annotations(inner_type) + # Pydantic models + if ( + inspect.isclass(clean_type) + and issubclass(clean_type, pydantic.BaseModel) + and isinstance(object_, typing.Mapping) + ): + return _convert_mapping(object_, clean_type, direction) + # TypedDicts + if typing_extensions.is_typeddict(clean_type) and isinstance( + object_, typing.Mapping + ): + return _convert_mapping(object_, clean_type, direction) + + if ( + typing_extensions.get_origin(clean_type) == typing.Dict + or typing_extensions.get_origin(clean_type) == dict + or clean_type == typing.Dict + ) and isinstance(object_, typing.Dict): + key_type = typing_extensions.get_args(clean_type)[0] + value_type = typing_extensions.get_args(clean_type)[1] + + return { + key: convert_and_respect_annotation_metadata( + object_=value, + annotation=annotation, + inner_type=value_type, + direction=direction, + ) + for key, value in object_.items() + } + + # If you're iterating on a string, do not bother to coerce it to a sequence. + if not isinstance(object_, str): + if ( + typing_extensions.get_origin(clean_type) == typing.Set + or typing_extensions.get_origin(clean_type) == set + or clean_type == typing.Set + ) and isinstance(object_, typing.Set): + inner_type = typing_extensions.get_args(clean_type)[0] + return { + convert_and_respect_annotation_metadata( + object_=item, + annotation=annotation, + inner_type=inner_type, + direction=direction, + ) + for item in object_ + } + elif ( + ( + typing_extensions.get_origin(clean_type) == typing.List + or typing_extensions.get_origin(clean_type) == list + or clean_type == typing.List + ) + and isinstance(object_, typing.List) + ) or ( + ( + typing_extensions.get_origin(clean_type) == typing.Sequence + or typing_extensions.get_origin(clean_type) == collections.abc.Sequence + or clean_type == typing.Sequence + ) + and isinstance(object_, typing.Sequence) + ): + inner_type = typing_extensions.get_args(clean_type)[0] + return [ + convert_and_respect_annotation_metadata( + object_=item, + annotation=annotation, + inner_type=inner_type, + direction=direction, + ) + for item in object_ + ] + + if typing_extensions.get_origin(clean_type) == typing.Union: + # We should be able to ~relatively~ safely try to convert keys against all + # member types in the union, the edge case here is if one member aliases a field + # of the same name to a different name from another member + # Or if another member aliases a field of the same name that another member does not. + for member in typing_extensions.get_args(clean_type): + object_ = convert_and_respect_annotation_metadata( + object_=object_, + annotation=annotation, + inner_type=member, + direction=direction, + ) + return object_ + + annotated_type = _get_annotation(annotation) + if annotated_type is None: + return object_ + + # If the object is not a TypedDict, a Union, or other container (list, set, sequence, etc.) + # Then we can safely call it on the recursive conversion. + return object_ + + +def _convert_mapping( + object_: typing.Mapping[str, object], + expected_type: typing.Any, + direction: typing.Literal["read", "write"], +) -> typing.Mapping[str, object]: + converted_object: typing.Dict[str, object] = {} + try: + annotations = typing_extensions.get_type_hints( + expected_type, include_extras=True + ) + except NameError: + # The TypedDict contains a circular reference, so + # we use the __annotations__ attribute directly. + annotations = getattr(expected_type, "__annotations__", {}) + aliases_to_field_names = _get_alias_to_field_name(annotations) + for key, value in object_.items(): + if direction == "read" and key in aliases_to_field_names: + dealiased_key = aliases_to_field_names.get(key) + if dealiased_key is not None: + type_ = annotations.get(dealiased_key) + else: + type_ = annotations.get(key) + # Note you can't get the annotation by the field name if you're in read mode, so you must check the aliases map + # + # So this is effectively saying if we're in write mode, and we don't have a type, or if we're in read mode and we don't have an alias + # then we can just pass the value through as is + if type_ is None: + converted_object[key] = value + elif direction == "read" and key not in aliases_to_field_names: + converted_object[key] = convert_and_respect_annotation_metadata( + object_=value, annotation=type_, direction=direction + ) + else: + converted_object[ + _alias_key(key, type_, direction, aliases_to_field_names) + ] = convert_and_respect_annotation_metadata( + object_=value, annotation=type_, direction=direction + ) + return converted_object + + +def _get_annotation(type_: typing.Any) -> typing.Optional[typing.Any]: + maybe_annotated_type = typing_extensions.get_origin(type_) + if maybe_annotated_type is None: + return None + + if maybe_annotated_type == typing_extensions.NotRequired: + type_ = typing_extensions.get_args(type_)[0] + maybe_annotated_type = typing_extensions.get_origin(type_) + + if maybe_annotated_type == typing_extensions.Annotated: + return type_ + + return None + + +def _remove_annotations(type_: typing.Any) -> typing.Any: + maybe_annotated_type = typing_extensions.get_origin(type_) + if maybe_annotated_type is None: + return type_ + + if maybe_annotated_type == typing_extensions.NotRequired: + return _remove_annotations(typing_extensions.get_args(type_)[0]) + + if maybe_annotated_type == typing_extensions.Annotated: + return _remove_annotations(typing_extensions.get_args(type_)[0]) + + return type_ + + +def get_alias_to_field_mapping(type_: typing.Any) -> typing.Dict[str, str]: + annotations = typing_extensions.get_type_hints(type_, include_extras=True) + return _get_alias_to_field_name(annotations) + + +def get_field_to_alias_mapping(type_: typing.Any) -> typing.Dict[str, str]: + annotations = typing_extensions.get_type_hints(type_, include_extras=True) + return _get_field_to_alias_name(annotations) + + +def _get_alias_to_field_name( + field_to_hint: typing.Dict[str, typing.Any], +) -> typing.Dict[str, str]: + aliases = {} + for field, hint in field_to_hint.items(): + maybe_alias = _get_alias_from_type(hint) + if maybe_alias is not None: + aliases[maybe_alias] = field + return aliases + + +def _get_field_to_alias_name( + field_to_hint: typing.Dict[str, typing.Any], +) -> typing.Dict[str, str]: + aliases = {} + for field, hint in field_to_hint.items(): + maybe_alias = _get_alias_from_type(hint) + if maybe_alias is not None: + aliases[field] = maybe_alias + return aliases + + +def _get_alias_from_type(type_: typing.Any) -> typing.Optional[str]: + maybe_annotated_type = _get_annotation(type_) + + if maybe_annotated_type is not None: + # The actual annotations are 1 onward, the first is the annotated type + annotations = typing_extensions.get_args(maybe_annotated_type)[1:] + + for annotation in annotations: + if isinstance(annotation, FieldMetadata) and annotation.alias is not None: + return annotation.alias + return None + + +def _alias_key( + key: str, + type_: typing.Any, + direction: typing.Literal["read", "write"], + aliases_to_field_names: typing.Dict[str, str], +) -> str: + if direction == "read": + return aliases_to_field_names.get(key, key) + return _get_alias_from_type(type_=type_) or key diff --git a/langfuse/api/dataset_items/__init__.py b/langfuse/api/dataset_items/__init__.py new file mode 100644 index 000000000..4d009d228 --- /dev/null +++ b/langfuse/api/dataset_items/__init__.py @@ -0,0 +1,52 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + CreateDatasetItemRequest, + DeleteDatasetItemResponse, + PaginatedDatasetItems, + ) +_dynamic_imports: typing.Dict[str, str] = { + "CreateDatasetItemRequest": ".types", + "DeleteDatasetItemResponse": ".types", + "PaginatedDatasetItems": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "CreateDatasetItemRequest", + "DeleteDatasetItemResponse", + "PaginatedDatasetItems", +] diff --git a/langfuse/api/dataset_items/client.py b/langfuse/api/dataset_items/client.py new file mode 100644 index 000000000..b21f1a4ee --- /dev/null +++ b/langfuse/api/dataset_items/client.py @@ -0,0 +1,482 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..commons.types.dataset_item import DatasetItem +from ..commons.types.dataset_status import DatasetStatus +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawDatasetItemsClient, RawDatasetItemsClient +from .types.delete_dataset_item_response import DeleteDatasetItemResponse +from .types.paginated_dataset_items import PaginatedDatasetItems + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class DatasetItemsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawDatasetItemsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawDatasetItemsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawDatasetItemsClient + """ + return self._raw_client + + def create( + self, + *, + dataset_name: str, + input: typing.Optional[typing.Any] = OMIT, + expected_output: typing.Optional[typing.Any] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + source_trace_id: typing.Optional[str] = OMIT, + source_observation_id: typing.Optional[str] = OMIT, + id: typing.Optional[str] = OMIT, + status: typing.Optional[DatasetStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> DatasetItem: + """ + Create a dataset item + + Parameters + ---------- + dataset_name : str + + input : typing.Optional[typing.Any] + + expected_output : typing.Optional[typing.Any] + + metadata : typing.Optional[typing.Any] + + source_trace_id : typing.Optional[str] + + source_observation_id : typing.Optional[str] + + id : typing.Optional[str] + Dataset items are upserted on their id. Id needs to be unique (project-level) and cannot be reused across datasets. + + status : typing.Optional[DatasetStatus] + Defaults to ACTIVE for newly created items + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DatasetItem + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.dataset_items.create( + dataset_name="datasetName", + ) + """ + _response = self._raw_client.create( + dataset_name=dataset_name, + input=input, + expected_output=expected_output, + metadata=metadata, + source_trace_id=source_trace_id, + source_observation_id=source_observation_id, + id=id, + status=status, + request_options=request_options, + ) + return _response.data + + def get( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> DatasetItem: + """ + Get a dataset item + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DatasetItem + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.dataset_items.get( + id="id", + ) + """ + _response = self._raw_client.get(id, request_options=request_options) + return _response.data + + def list( + self, + *, + dataset_name: typing.Optional[str] = None, + source_trace_id: typing.Optional[str] = None, + source_observation_id: typing.Optional[str] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedDatasetItems: + """ + Get dataset items + + Parameters + ---------- + dataset_name : typing.Optional[str] + + source_trace_id : typing.Optional[str] + + source_observation_id : typing.Optional[str] + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedDatasetItems + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.dataset_items.list() + """ + _response = self._raw_client.list( + dataset_name=dataset_name, + source_trace_id=source_trace_id, + source_observation_id=source_observation_id, + page=page, + limit=limit, + request_options=request_options, + ) + return _response.data + + def delete( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> DeleteDatasetItemResponse: + """ + Delete a dataset item and all its run items. This action is irreversible. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteDatasetItemResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.dataset_items.delete( + id="id", + ) + """ + _response = self._raw_client.delete(id, request_options=request_options) + return _response.data + + +class AsyncDatasetItemsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawDatasetItemsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawDatasetItemsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawDatasetItemsClient + """ + return self._raw_client + + async def create( + self, + *, + dataset_name: str, + input: typing.Optional[typing.Any] = OMIT, + expected_output: typing.Optional[typing.Any] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + source_trace_id: typing.Optional[str] = OMIT, + source_observation_id: typing.Optional[str] = OMIT, + id: typing.Optional[str] = OMIT, + status: typing.Optional[DatasetStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> DatasetItem: + """ + Create a dataset item + + Parameters + ---------- + dataset_name : str + + input : typing.Optional[typing.Any] + + expected_output : typing.Optional[typing.Any] + + metadata : typing.Optional[typing.Any] + + source_trace_id : typing.Optional[str] + + source_observation_id : typing.Optional[str] + + id : typing.Optional[str] + Dataset items are upserted on their id. Id needs to be unique (project-level) and cannot be reused across datasets. + + status : typing.Optional[DatasetStatus] + Defaults to ACTIVE for newly created items + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DatasetItem + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.dataset_items.create( + dataset_name="datasetName", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create( + dataset_name=dataset_name, + input=input, + expected_output=expected_output, + metadata=metadata, + source_trace_id=source_trace_id, + source_observation_id=source_observation_id, + id=id, + status=status, + request_options=request_options, + ) + return _response.data + + async def get( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> DatasetItem: + """ + Get a dataset item + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DatasetItem + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.dataset_items.get( + id="id", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get(id, request_options=request_options) + return _response.data + + async def list( + self, + *, + dataset_name: typing.Optional[str] = None, + source_trace_id: typing.Optional[str] = None, + source_observation_id: typing.Optional[str] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedDatasetItems: + """ + Get dataset items + + Parameters + ---------- + dataset_name : typing.Optional[str] + + source_trace_id : typing.Optional[str] + + source_observation_id : typing.Optional[str] + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedDatasetItems + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.dataset_items.list() + + + asyncio.run(main()) + """ + _response = await self._raw_client.list( + dataset_name=dataset_name, + source_trace_id=source_trace_id, + source_observation_id=source_observation_id, + page=page, + limit=limit, + request_options=request_options, + ) + return _response.data + + async def delete( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> DeleteDatasetItemResponse: + """ + Delete a dataset item and all its run items. This action is irreversible. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteDatasetItemResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.dataset_items.delete( + id="id", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete(id, request_options=request_options) + return _response.data diff --git a/langfuse/api/dataset_items/raw_client.py b/langfuse/api/dataset_items/raw_client.py new file mode 100644 index 000000000..1dede7c90 --- /dev/null +++ b/langfuse/api/dataset_items/raw_client.py @@ -0,0 +1,955 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..commons.types.dataset_item import DatasetItem +from ..commons.types.dataset_status import DatasetStatus +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.delete_dataset_item_response import DeleteDatasetItemResponse +from .types.paginated_dataset_items import PaginatedDatasetItems + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawDatasetItemsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def create( + self, + *, + dataset_name: str, + input: typing.Optional[typing.Any] = OMIT, + expected_output: typing.Optional[typing.Any] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + source_trace_id: typing.Optional[str] = OMIT, + source_observation_id: typing.Optional[str] = OMIT, + id: typing.Optional[str] = OMIT, + status: typing.Optional[DatasetStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[DatasetItem]: + """ + Create a dataset item + + Parameters + ---------- + dataset_name : str + + input : typing.Optional[typing.Any] + + expected_output : typing.Optional[typing.Any] + + metadata : typing.Optional[typing.Any] + + source_trace_id : typing.Optional[str] + + source_observation_id : typing.Optional[str] + + id : typing.Optional[str] + Dataset items are upserted on their id. Id needs to be unique (project-level) and cannot be reused across datasets. + + status : typing.Optional[DatasetStatus] + Defaults to ACTIVE for newly created items + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DatasetItem] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/dataset-items", + method="POST", + json={ + "datasetName": dataset_name, + "input": input, + "expectedOutput": expected_output, + "metadata": metadata, + "sourceTraceId": source_trace_id, + "sourceObservationId": source_observation_id, + "id": id, + "status": status, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DatasetItem, + parse_obj_as( + type_=DatasetItem, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[DatasetItem]: + """ + Get a dataset item + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DatasetItem] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/dataset-items/{jsonable_encoder(id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DatasetItem, + parse_obj_as( + type_=DatasetItem, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def list( + self, + *, + dataset_name: typing.Optional[str] = None, + source_trace_id: typing.Optional[str] = None, + source_observation_id: typing.Optional[str] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[PaginatedDatasetItems]: + """ + Get dataset items + + Parameters + ---------- + dataset_name : typing.Optional[str] + + source_trace_id : typing.Optional[str] + + source_observation_id : typing.Optional[str] + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[PaginatedDatasetItems] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/dataset-items", + method="GET", + params={ + "datasetName": dataset_name, + "sourceTraceId": source_trace_id, + "sourceObservationId": source_observation_id, + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedDatasetItems, + parse_obj_as( + type_=PaginatedDatasetItems, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[DeleteDatasetItemResponse]: + """ + Delete a dataset item and all its run items. This action is irreversible. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DeleteDatasetItemResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/dataset-items/{jsonable_encoder(id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteDatasetItemResponse, + parse_obj_as( + type_=DeleteDatasetItemResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawDatasetItemsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def create( + self, + *, + dataset_name: str, + input: typing.Optional[typing.Any] = OMIT, + expected_output: typing.Optional[typing.Any] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + source_trace_id: typing.Optional[str] = OMIT, + source_observation_id: typing.Optional[str] = OMIT, + id: typing.Optional[str] = OMIT, + status: typing.Optional[DatasetStatus] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[DatasetItem]: + """ + Create a dataset item + + Parameters + ---------- + dataset_name : str + + input : typing.Optional[typing.Any] + + expected_output : typing.Optional[typing.Any] + + metadata : typing.Optional[typing.Any] + + source_trace_id : typing.Optional[str] + + source_observation_id : typing.Optional[str] + + id : typing.Optional[str] + Dataset items are upserted on their id. Id needs to be unique (project-level) and cannot be reused across datasets. + + status : typing.Optional[DatasetStatus] + Defaults to ACTIVE for newly created items + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DatasetItem] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/dataset-items", + method="POST", + json={ + "datasetName": dataset_name, + "input": input, + "expectedOutput": expected_output, + "metadata": metadata, + "sourceTraceId": source_trace_id, + "sourceObservationId": source_observation_id, + "id": id, + "status": status, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DatasetItem, + parse_obj_as( + type_=DatasetItem, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[DatasetItem]: + """ + Get a dataset item + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DatasetItem] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/dataset-items/{jsonable_encoder(id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DatasetItem, + parse_obj_as( + type_=DatasetItem, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def list( + self, + *, + dataset_name: typing.Optional[str] = None, + source_trace_id: typing.Optional[str] = None, + source_observation_id: typing.Optional[str] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[PaginatedDatasetItems]: + """ + Get dataset items + + Parameters + ---------- + dataset_name : typing.Optional[str] + + source_trace_id : typing.Optional[str] + + source_observation_id : typing.Optional[str] + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[PaginatedDatasetItems] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/dataset-items", + method="GET", + params={ + "datasetName": dataset_name, + "sourceTraceId": source_trace_id, + "sourceObservationId": source_observation_id, + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedDatasetItems, + parse_obj_as( + type_=PaginatedDatasetItems, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[DeleteDatasetItemResponse]: + """ + Delete a dataset item and all its run items. This action is irreversible. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DeleteDatasetItemResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/dataset-items/{jsonable_encoder(id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteDatasetItemResponse, + parse_obj_as( + type_=DeleteDatasetItemResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/dataset_items/types/__init__.py b/langfuse/api/dataset_items/types/__init__.py new file mode 100644 index 000000000..c7ce59bf4 --- /dev/null +++ b/langfuse/api/dataset_items/types/__init__.py @@ -0,0 +1,50 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .create_dataset_item_request import CreateDatasetItemRequest + from .delete_dataset_item_response import DeleteDatasetItemResponse + from .paginated_dataset_items import PaginatedDatasetItems +_dynamic_imports: typing.Dict[str, str] = { + "CreateDatasetItemRequest": ".create_dataset_item_request", + "DeleteDatasetItemResponse": ".delete_dataset_item_response", + "PaginatedDatasetItems": ".paginated_dataset_items", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "CreateDatasetItemRequest", + "DeleteDatasetItemResponse", + "PaginatedDatasetItems", +] diff --git a/langfuse/api/dataset_items/types/create_dataset_item_request.py b/langfuse/api/dataset_items/types/create_dataset_item_request.py new file mode 100644 index 000000000..43496034e --- /dev/null +++ b/langfuse/api/dataset_items/types/create_dataset_item_request.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...commons.types.dataset_status import DatasetStatus +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class CreateDatasetItemRequest(UniversalBaseModel): + dataset_name: typing_extensions.Annotated[str, FieldMetadata(alias="datasetName")] + input: typing.Optional[typing.Any] = None + expected_output: typing_extensions.Annotated[ + typing.Optional[typing.Any], FieldMetadata(alias="expectedOutput") + ] = None + metadata: typing.Optional[typing.Any] = None + source_trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sourceTraceId") + ] = None + source_observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sourceObservationId") + ] = None + id: typing.Optional[str] = pydantic.Field(default=None) + """ + Dataset items are upserted on their id. Id needs to be unique (project-level) and cannot be reused across datasets. + """ + + status: typing.Optional[DatasetStatus] = pydantic.Field(default=None) + """ + Defaults to ACTIVE for newly created items + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/dataset_items/types/delete_dataset_item_response.py b/langfuse/api/dataset_items/types/delete_dataset_item_response.py new file mode 100644 index 000000000..5d392540b --- /dev/null +++ b/langfuse/api/dataset_items/types/delete_dataset_item_response.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class DeleteDatasetItemResponse(UniversalBaseModel): + message: str = pydantic.Field() + """ + Success message after deletion + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/dataset_items/types/paginated_dataset_items.py b/langfuse/api/dataset_items/types/paginated_dataset_items.py new file mode 100644 index 000000000..547796a4d --- /dev/null +++ b/langfuse/api/dataset_items/types/paginated_dataset_items.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.dataset_item import DatasetItem +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse + + +class PaginatedDatasetItems(UniversalBaseModel): + data: typing.List[DatasetItem] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/dataset_run_items/__init__.py b/langfuse/api/dataset_run_items/__init__.py new file mode 100644 index 000000000..9ff4e097e --- /dev/null +++ b/langfuse/api/dataset_run_items/__init__.py @@ -0,0 +1,43 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import CreateDatasetRunItemRequest, PaginatedDatasetRunItems +_dynamic_imports: typing.Dict[str, str] = { + "CreateDatasetRunItemRequest": ".types", + "PaginatedDatasetRunItems": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["CreateDatasetRunItemRequest", "PaginatedDatasetRunItems"] diff --git a/langfuse/api/dataset_run_items/client.py b/langfuse/api/dataset_run_items/client.py new file mode 100644 index 000000000..e033ebbc8 --- /dev/null +++ b/langfuse/api/dataset_run_items/client.py @@ -0,0 +1,306 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..commons.types.dataset_run_item import DatasetRunItem +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawDatasetRunItemsClient, RawDatasetRunItemsClient +from .types.paginated_dataset_run_items import PaginatedDatasetRunItems + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class DatasetRunItemsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawDatasetRunItemsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawDatasetRunItemsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawDatasetRunItemsClient + """ + return self._raw_client + + def create( + self, + *, + run_name: str, + dataset_item_id: str, + run_description: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + observation_id: typing.Optional[str] = OMIT, + trace_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> DatasetRunItem: + """ + Create a dataset run item + + Parameters + ---------- + run_name : str + + dataset_item_id : str + + run_description : typing.Optional[str] + Description of the run. If run exists, description will be updated. + + metadata : typing.Optional[typing.Any] + Metadata of the dataset run, updates run if run already exists + + observation_id : typing.Optional[str] + + trace_id : typing.Optional[str] + traceId should always be provided. For compatibility with older SDK versions it can also be inferred from the provided observationId. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DatasetRunItem + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.dataset_run_items.create( + run_name="runName", + dataset_item_id="datasetItemId", + ) + """ + _response = self._raw_client.create( + run_name=run_name, + dataset_item_id=dataset_item_id, + run_description=run_description, + metadata=metadata, + observation_id=observation_id, + trace_id=trace_id, + request_options=request_options, + ) + return _response.data + + def list( + self, + *, + dataset_id: str, + run_name: str, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedDatasetRunItems: + """ + List dataset run items + + Parameters + ---------- + dataset_id : str + + run_name : str + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedDatasetRunItems + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.dataset_run_items.list( + dataset_id="datasetId", + run_name="runName", + ) + """ + _response = self._raw_client.list( + dataset_id=dataset_id, + run_name=run_name, + page=page, + limit=limit, + request_options=request_options, + ) + return _response.data + + +class AsyncDatasetRunItemsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawDatasetRunItemsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawDatasetRunItemsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawDatasetRunItemsClient + """ + return self._raw_client + + async def create( + self, + *, + run_name: str, + dataset_item_id: str, + run_description: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + observation_id: typing.Optional[str] = OMIT, + trace_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> DatasetRunItem: + """ + Create a dataset run item + + Parameters + ---------- + run_name : str + + dataset_item_id : str + + run_description : typing.Optional[str] + Description of the run. If run exists, description will be updated. + + metadata : typing.Optional[typing.Any] + Metadata of the dataset run, updates run if run already exists + + observation_id : typing.Optional[str] + + trace_id : typing.Optional[str] + traceId should always be provided. For compatibility with older SDK versions it can also be inferred from the provided observationId. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DatasetRunItem + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.dataset_run_items.create( + run_name="runName", + dataset_item_id="datasetItemId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create( + run_name=run_name, + dataset_item_id=dataset_item_id, + run_description=run_description, + metadata=metadata, + observation_id=observation_id, + trace_id=trace_id, + request_options=request_options, + ) + return _response.data + + async def list( + self, + *, + dataset_id: str, + run_name: str, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedDatasetRunItems: + """ + List dataset run items + + Parameters + ---------- + dataset_id : str + + run_name : str + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedDatasetRunItems + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.dataset_run_items.list( + dataset_id="datasetId", + run_name="runName", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.list( + dataset_id=dataset_id, + run_name=run_name, + page=page, + limit=limit, + request_options=request_options, + ) + return _response.data diff --git a/langfuse/api/dataset_run_items/raw_client.py b/langfuse/api/dataset_run_items/raw_client.py new file mode 100644 index 000000000..17a7e29f0 --- /dev/null +++ b/langfuse/api/dataset_run_items/raw_client.py @@ -0,0 +1,530 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..commons.types.dataset_run_item import DatasetRunItem +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.paginated_dataset_run_items import PaginatedDatasetRunItems + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawDatasetRunItemsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def create( + self, + *, + run_name: str, + dataset_item_id: str, + run_description: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + observation_id: typing.Optional[str] = OMIT, + trace_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[DatasetRunItem]: + """ + Create a dataset run item + + Parameters + ---------- + run_name : str + + dataset_item_id : str + + run_description : typing.Optional[str] + Description of the run. If run exists, description will be updated. + + metadata : typing.Optional[typing.Any] + Metadata of the dataset run, updates run if run already exists + + observation_id : typing.Optional[str] + + trace_id : typing.Optional[str] + traceId should always be provided. For compatibility with older SDK versions it can also be inferred from the provided observationId. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DatasetRunItem] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/dataset-run-items", + method="POST", + json={ + "runName": run_name, + "runDescription": run_description, + "metadata": metadata, + "datasetItemId": dataset_item_id, + "observationId": observation_id, + "traceId": trace_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DatasetRunItem, + parse_obj_as( + type_=DatasetRunItem, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def list( + self, + *, + dataset_id: str, + run_name: str, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[PaginatedDatasetRunItems]: + """ + List dataset run items + + Parameters + ---------- + dataset_id : str + + run_name : str + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[PaginatedDatasetRunItems] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/dataset-run-items", + method="GET", + params={ + "datasetId": dataset_id, + "runName": run_name, + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedDatasetRunItems, + parse_obj_as( + type_=PaginatedDatasetRunItems, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawDatasetRunItemsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def create( + self, + *, + run_name: str, + dataset_item_id: str, + run_description: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + observation_id: typing.Optional[str] = OMIT, + trace_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[DatasetRunItem]: + """ + Create a dataset run item + + Parameters + ---------- + run_name : str + + dataset_item_id : str + + run_description : typing.Optional[str] + Description of the run. If run exists, description will be updated. + + metadata : typing.Optional[typing.Any] + Metadata of the dataset run, updates run if run already exists + + observation_id : typing.Optional[str] + + trace_id : typing.Optional[str] + traceId should always be provided. For compatibility with older SDK versions it can also be inferred from the provided observationId. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DatasetRunItem] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/dataset-run-items", + method="POST", + json={ + "runName": run_name, + "runDescription": run_description, + "metadata": metadata, + "datasetItemId": dataset_item_id, + "observationId": observation_id, + "traceId": trace_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DatasetRunItem, + parse_obj_as( + type_=DatasetRunItem, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def list( + self, + *, + dataset_id: str, + run_name: str, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[PaginatedDatasetRunItems]: + """ + List dataset run items + + Parameters + ---------- + dataset_id : str + + run_name : str + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[PaginatedDatasetRunItems] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/dataset-run-items", + method="GET", + params={ + "datasetId": dataset_id, + "runName": run_name, + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedDatasetRunItems, + parse_obj_as( + type_=PaginatedDatasetRunItems, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/dataset_run_items/types/__init__.py b/langfuse/api/dataset_run_items/types/__init__.py new file mode 100644 index 000000000..b520924c0 --- /dev/null +++ b/langfuse/api/dataset_run_items/types/__init__.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .create_dataset_run_item_request import CreateDatasetRunItemRequest + from .paginated_dataset_run_items import PaginatedDatasetRunItems +_dynamic_imports: typing.Dict[str, str] = { + "CreateDatasetRunItemRequest": ".create_dataset_run_item_request", + "PaginatedDatasetRunItems": ".paginated_dataset_run_items", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["CreateDatasetRunItemRequest", "PaginatedDatasetRunItems"] diff --git a/langfuse/api/dataset_run_items/types/create_dataset_run_item_request.py b/langfuse/api/dataset_run_items/types/create_dataset_run_item_request.py new file mode 100644 index 000000000..3cd63ec70 --- /dev/null +++ b/langfuse/api/dataset_run_items/types/create_dataset_run_item_request.py @@ -0,0 +1,47 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class CreateDatasetRunItemRequest(UniversalBaseModel): + run_name: typing_extensions.Annotated[str, FieldMetadata(alias="runName")] + run_description: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="runDescription") + ] = pydantic.Field(default=None) + """ + Description of the run. If run exists, description will be updated. + """ + + metadata: typing.Optional[typing.Any] = pydantic.Field(default=None) + """ + Metadata of the dataset run, updates run if run already exists + """ + + dataset_item_id: typing_extensions.Annotated[ + str, FieldMetadata(alias="datasetItemId") + ] + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = pydantic.Field(default=None) + """ + traceId should always be provided. For compatibility with older SDK versions it can also be inferred from the provided observationId. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/dataset_run_items/types/paginated_dataset_run_items.py b/langfuse/api/dataset_run_items/types/paginated_dataset_run_items.py new file mode 100644 index 000000000..0a7e61f43 --- /dev/null +++ b/langfuse/api/dataset_run_items/types/paginated_dataset_run_items.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.dataset_run_item import DatasetRunItem +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse + + +class PaginatedDatasetRunItems(UniversalBaseModel): + data: typing.List[DatasetRunItem] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/datasets/__init__.py b/langfuse/api/datasets/__init__.py new file mode 100644 index 000000000..e9005285e --- /dev/null +++ b/langfuse/api/datasets/__init__.py @@ -0,0 +1,55 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + CreateDatasetRequest, + DeleteDatasetRunResponse, + PaginatedDatasetRuns, + PaginatedDatasets, + ) +_dynamic_imports: typing.Dict[str, str] = { + "CreateDatasetRequest": ".types", + "DeleteDatasetRunResponse": ".types", + "PaginatedDatasetRuns": ".types", + "PaginatedDatasets": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "CreateDatasetRequest", + "DeleteDatasetRunResponse", + "PaginatedDatasetRuns", + "PaginatedDatasets", +] diff --git a/langfuse/api/datasets/client.py b/langfuse/api/datasets/client.py new file mode 100644 index 000000000..859ee0fe7 --- /dev/null +++ b/langfuse/api/datasets/client.py @@ -0,0 +1,661 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..commons.types.dataset import Dataset +from ..commons.types.dataset_run_with_items import DatasetRunWithItems +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawDatasetsClient, RawDatasetsClient +from .types.delete_dataset_run_response import DeleteDatasetRunResponse +from .types.paginated_dataset_runs import PaginatedDatasetRuns +from .types.paginated_datasets import PaginatedDatasets + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class DatasetsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawDatasetsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawDatasetsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawDatasetsClient + """ + return self._raw_client + + def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedDatasets: + """ + Get all datasets + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedDatasets + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.datasets.list() + """ + _response = self._raw_client.list( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + def get( + self, + dataset_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> Dataset: + """ + Get a dataset + + Parameters + ---------- + dataset_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Dataset + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.datasets.get( + dataset_name="datasetName", + ) + """ + _response = self._raw_client.get(dataset_name, request_options=request_options) + return _response.data + + def create( + self, + *, + name: str, + description: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + input_schema: typing.Optional[typing.Any] = OMIT, + expected_output_schema: typing.Optional[typing.Any] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Dataset: + """ + Create a dataset + + Parameters + ---------- + name : str + + description : typing.Optional[str] + + metadata : typing.Optional[typing.Any] + + input_schema : typing.Optional[typing.Any] + JSON Schema for validating dataset item inputs. When set, all new and existing dataset items will be validated against this schema. + + expected_output_schema : typing.Optional[typing.Any] + JSON Schema for validating dataset item expected outputs. When set, all new and existing dataset items will be validated against this schema. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Dataset + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.datasets.create( + name="name", + ) + """ + _response = self._raw_client.create( + name=name, + description=description, + metadata=metadata, + input_schema=input_schema, + expected_output_schema=expected_output_schema, + request_options=request_options, + ) + return _response.data + + def get_run( + self, + dataset_name: str, + run_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> DatasetRunWithItems: + """ + Get a dataset run and its items + + Parameters + ---------- + dataset_name : str + + run_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DatasetRunWithItems + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.datasets.get_run( + dataset_name="datasetName", + run_name="runName", + ) + """ + _response = self._raw_client.get_run( + dataset_name, run_name, request_options=request_options + ) + return _response.data + + def delete_run( + self, + dataset_name: str, + run_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> DeleteDatasetRunResponse: + """ + Delete a dataset run and all its run items. This action is irreversible. + + Parameters + ---------- + dataset_name : str + + run_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteDatasetRunResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.datasets.delete_run( + dataset_name="datasetName", + run_name="runName", + ) + """ + _response = self._raw_client.delete_run( + dataset_name, run_name, request_options=request_options + ) + return _response.data + + def get_runs( + self, + dataset_name: str, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedDatasetRuns: + """ + Get dataset runs + + Parameters + ---------- + dataset_name : str + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedDatasetRuns + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.datasets.get_runs( + dataset_name="datasetName", + ) + """ + _response = self._raw_client.get_runs( + dataset_name, page=page, limit=limit, request_options=request_options + ) + return _response.data + + +class AsyncDatasetsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawDatasetsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawDatasetsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawDatasetsClient + """ + return self._raw_client + + async def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedDatasets: + """ + Get all datasets + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedDatasets + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.datasets.list() + + + asyncio.run(main()) + """ + _response = await self._raw_client.list( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + async def get( + self, + dataset_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> Dataset: + """ + Get a dataset + + Parameters + ---------- + dataset_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Dataset + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.datasets.get( + dataset_name="datasetName", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get( + dataset_name, request_options=request_options + ) + return _response.data + + async def create( + self, + *, + name: str, + description: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + input_schema: typing.Optional[typing.Any] = OMIT, + expected_output_schema: typing.Optional[typing.Any] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Dataset: + """ + Create a dataset + + Parameters + ---------- + name : str + + description : typing.Optional[str] + + metadata : typing.Optional[typing.Any] + + input_schema : typing.Optional[typing.Any] + JSON Schema for validating dataset item inputs. When set, all new and existing dataset items will be validated against this schema. + + expected_output_schema : typing.Optional[typing.Any] + JSON Schema for validating dataset item expected outputs. When set, all new and existing dataset items will be validated against this schema. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Dataset + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.datasets.create( + name="name", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create( + name=name, + description=description, + metadata=metadata, + input_schema=input_schema, + expected_output_schema=expected_output_schema, + request_options=request_options, + ) + return _response.data + + async def get_run( + self, + dataset_name: str, + run_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> DatasetRunWithItems: + """ + Get a dataset run and its items + + Parameters + ---------- + dataset_name : str + + run_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DatasetRunWithItems + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.datasets.get_run( + dataset_name="datasetName", + run_name="runName", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_run( + dataset_name, run_name, request_options=request_options + ) + return _response.data + + async def delete_run( + self, + dataset_name: str, + run_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> DeleteDatasetRunResponse: + """ + Delete a dataset run and all its run items. This action is irreversible. + + Parameters + ---------- + dataset_name : str + + run_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + DeleteDatasetRunResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.datasets.delete_run( + dataset_name="datasetName", + run_name="runName", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete_run( + dataset_name, run_name, request_options=request_options + ) + return _response.data + + async def get_runs( + self, + dataset_name: str, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedDatasetRuns: + """ + Get dataset runs + + Parameters + ---------- + dataset_name : str + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedDatasetRuns + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.datasets.get_runs( + dataset_name="datasetName", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_runs( + dataset_name, page=page, limit=limit, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/datasets/raw_client.py b/langfuse/api/datasets/raw_client.py new file mode 100644 index 000000000..306ad8f76 --- /dev/null +++ b/langfuse/api/datasets/raw_client.py @@ -0,0 +1,1368 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..commons.types.dataset import Dataset +from ..commons.types.dataset_run_with_items import DatasetRunWithItems +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.delete_dataset_run_response import DeleteDatasetRunResponse +from .types.paginated_dataset_runs import PaginatedDatasetRuns +from .types.paginated_datasets import PaginatedDatasets + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawDatasetsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[PaginatedDatasets]: + """ + Get all datasets + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[PaginatedDatasets] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/v2/datasets", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedDatasets, + parse_obj_as( + type_=PaginatedDatasets, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get( + self, + dataset_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Dataset]: + """ + Get a dataset + + Parameters + ---------- + dataset_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Dataset] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/v2/datasets/{jsonable_encoder(dataset_name)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Dataset, + parse_obj_as( + type_=Dataset, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def create( + self, + *, + name: str, + description: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + input_schema: typing.Optional[typing.Any] = OMIT, + expected_output_schema: typing.Optional[typing.Any] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Dataset]: + """ + Create a dataset + + Parameters + ---------- + name : str + + description : typing.Optional[str] + + metadata : typing.Optional[typing.Any] + + input_schema : typing.Optional[typing.Any] + JSON Schema for validating dataset item inputs. When set, all new and existing dataset items will be validated against this schema. + + expected_output_schema : typing.Optional[typing.Any] + JSON Schema for validating dataset item expected outputs. When set, all new and existing dataset items will be validated against this schema. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Dataset] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/v2/datasets", + method="POST", + json={ + "name": name, + "description": description, + "metadata": metadata, + "inputSchema": input_schema, + "expectedOutputSchema": expected_output_schema, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Dataset, + parse_obj_as( + type_=Dataset, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_run( + self, + dataset_name: str, + run_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[DatasetRunWithItems]: + """ + Get a dataset run and its items + + Parameters + ---------- + dataset_name : str + + run_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DatasetRunWithItems] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs/{jsonable_encoder(run_name)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DatasetRunWithItems, + parse_obj_as( + type_=DatasetRunWithItems, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete_run( + self, + dataset_name: str, + run_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[DeleteDatasetRunResponse]: + """ + Delete a dataset run and all its run items. This action is irreversible. + + Parameters + ---------- + dataset_name : str + + run_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DeleteDatasetRunResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs/{jsonable_encoder(run_name)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteDatasetRunResponse, + parse_obj_as( + type_=DeleteDatasetRunResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_runs( + self, + dataset_name: str, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[PaginatedDatasetRuns]: + """ + Get dataset runs + + Parameters + ---------- + dataset_name : str + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[PaginatedDatasetRuns] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedDatasetRuns, + parse_obj_as( + type_=PaginatedDatasetRuns, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawDatasetsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[PaginatedDatasets]: + """ + Get all datasets + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[PaginatedDatasets] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/v2/datasets", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedDatasets, + parse_obj_as( + type_=PaginatedDatasets, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get( + self, + dataset_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Dataset]: + """ + Get a dataset + + Parameters + ---------- + dataset_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Dataset] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/v2/datasets/{jsonable_encoder(dataset_name)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Dataset, + parse_obj_as( + type_=Dataset, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def create( + self, + *, + name: str, + description: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Any] = OMIT, + input_schema: typing.Optional[typing.Any] = OMIT, + expected_output_schema: typing.Optional[typing.Any] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Dataset]: + """ + Create a dataset + + Parameters + ---------- + name : str + + description : typing.Optional[str] + + metadata : typing.Optional[typing.Any] + + input_schema : typing.Optional[typing.Any] + JSON Schema for validating dataset item inputs. When set, all new and existing dataset items will be validated against this schema. + + expected_output_schema : typing.Optional[typing.Any] + JSON Schema for validating dataset item expected outputs. When set, all new and existing dataset items will be validated against this schema. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Dataset] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/v2/datasets", + method="POST", + json={ + "name": name, + "description": description, + "metadata": metadata, + "inputSchema": input_schema, + "expectedOutputSchema": expected_output_schema, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Dataset, + parse_obj_as( + type_=Dataset, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_run( + self, + dataset_name: str, + run_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[DatasetRunWithItems]: + """ + Get a dataset run and its items + + Parameters + ---------- + dataset_name : str + + run_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DatasetRunWithItems] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs/{jsonable_encoder(run_name)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DatasetRunWithItems, + parse_obj_as( + type_=DatasetRunWithItems, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete_run( + self, + dataset_name: str, + run_name: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[DeleteDatasetRunResponse]: + """ + Delete a dataset run and all its run items. This action is irreversible. + + Parameters + ---------- + dataset_name : str + + run_name : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DeleteDatasetRunResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs/{jsonable_encoder(run_name)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteDatasetRunResponse, + parse_obj_as( + type_=DeleteDatasetRunResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_runs( + self, + dataset_name: str, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[PaginatedDatasetRuns]: + """ + Get dataset runs + + Parameters + ---------- + dataset_name : str + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[PaginatedDatasetRuns] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedDatasetRuns, + parse_obj_as( + type_=PaginatedDatasetRuns, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/datasets/types/__init__.py b/langfuse/api/datasets/types/__init__.py new file mode 100644 index 000000000..60c58934a --- /dev/null +++ b/langfuse/api/datasets/types/__init__.py @@ -0,0 +1,53 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .create_dataset_request import CreateDatasetRequest + from .delete_dataset_run_response import DeleteDatasetRunResponse + from .paginated_dataset_runs import PaginatedDatasetRuns + from .paginated_datasets import PaginatedDatasets +_dynamic_imports: typing.Dict[str, str] = { + "CreateDatasetRequest": ".create_dataset_request", + "DeleteDatasetRunResponse": ".delete_dataset_run_response", + "PaginatedDatasetRuns": ".paginated_dataset_runs", + "PaginatedDatasets": ".paginated_datasets", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "CreateDatasetRequest", + "DeleteDatasetRunResponse", + "PaginatedDatasetRuns", + "PaginatedDatasets", +] diff --git a/langfuse/api/datasets/types/create_dataset_request.py b/langfuse/api/datasets/types/create_dataset_request.py new file mode 100644 index 000000000..d27b4aaa6 --- /dev/null +++ b/langfuse/api/datasets/types/create_dataset_request.py @@ -0,0 +1,38 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class CreateDatasetRequest(UniversalBaseModel): + name: str + description: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + input_schema: typing_extensions.Annotated[ + typing.Optional[typing.Any], FieldMetadata(alias="inputSchema") + ] = pydantic.Field(default=None) + """ + JSON Schema for validating dataset item inputs. When set, all new and existing dataset items will be validated against this schema. + """ + + expected_output_schema: typing_extensions.Annotated[ + typing.Optional[typing.Any], FieldMetadata(alias="expectedOutputSchema") + ] = pydantic.Field(default=None) + """ + JSON Schema for validating dataset item expected outputs. When set, all new and existing dataset items will be validated against this schema. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/datasets/types/delete_dataset_run_response.py b/langfuse/api/datasets/types/delete_dataset_run_response.py new file mode 100644 index 000000000..cf1dbfc71 --- /dev/null +++ b/langfuse/api/datasets/types/delete_dataset_run_response.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class DeleteDatasetRunResponse(UniversalBaseModel): + message: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/datasets/types/paginated_dataset_runs.py b/langfuse/api/datasets/types/paginated_dataset_runs.py new file mode 100644 index 000000000..154c75248 --- /dev/null +++ b/langfuse/api/datasets/types/paginated_dataset_runs.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.dataset_run import DatasetRun +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse + + +class PaginatedDatasetRuns(UniversalBaseModel): + data: typing.List[DatasetRun] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/datasets/types/paginated_datasets.py b/langfuse/api/datasets/types/paginated_datasets.py new file mode 100644 index 000000000..bad6c2ded --- /dev/null +++ b/langfuse/api/datasets/types/paginated_datasets.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.dataset import Dataset +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse + + +class PaginatedDatasets(UniversalBaseModel): + data: typing.List[Dataset] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/health/__init__.py b/langfuse/api/health/__init__.py new file mode 100644 index 000000000..2a101c5f7 --- /dev/null +++ b/langfuse/api/health/__init__.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import HealthResponse + from .errors import ServiceUnavailableError +_dynamic_imports: typing.Dict[str, str] = { + "HealthResponse": ".types", + "ServiceUnavailableError": ".errors", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["HealthResponse", "ServiceUnavailableError"] diff --git a/langfuse/api/health/client.py b/langfuse/api/health/client.py new file mode 100644 index 000000000..7406fef6f --- /dev/null +++ b/langfuse/api/health/client.py @@ -0,0 +1,112 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawHealthClient, RawHealthClient +from .types.health_response import HealthResponse + + +class HealthClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawHealthClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawHealthClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawHealthClient + """ + return self._raw_client + + def health( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HealthResponse: + """ + Check health of API and database + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HealthResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.health.health() + """ + _response = self._raw_client.health(request_options=request_options) + return _response.data + + +class AsyncHealthClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawHealthClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawHealthClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawHealthClient + """ + return self._raw_client + + async def health( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HealthResponse: + """ + Check health of API and database + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HealthResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.health.health() + + + asyncio.run(main()) + """ + _response = await self._raw_client.health(request_options=request_options) + return _response.data diff --git a/langfuse/api/health/errors/__init__.py b/langfuse/api/health/errors/__init__.py new file mode 100644 index 000000000..3567f86b3 --- /dev/null +++ b/langfuse/api/health/errors/__init__.py @@ -0,0 +1,42 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .service_unavailable_error import ServiceUnavailableError +_dynamic_imports: typing.Dict[str, str] = { + "ServiceUnavailableError": ".service_unavailable_error" +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["ServiceUnavailableError"] diff --git a/langfuse/api/health/errors/service_unavailable_error.py b/langfuse/api/health/errors/service_unavailable_error.py new file mode 100644 index 000000000..68d5d836e --- /dev/null +++ b/langfuse/api/health/errors/service_unavailable_error.py @@ -0,0 +1,13 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ...core.api_error import ApiError + + +class ServiceUnavailableError(ApiError): + def __init__(self, headers: typing.Optional[typing.Dict[str, str]] = None): + super().__init__( + status_code=503, + headers=headers, + ) diff --git a/langfuse/api/health/raw_client.py b/langfuse/api/health/raw_client.py new file mode 100644 index 000000000..afeef1a96 --- /dev/null +++ b/langfuse/api/health/raw_client.py @@ -0,0 +1,227 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .errors.service_unavailable_error import ServiceUnavailableError +from .types.health_response import HealthResponse + + +class RawHealthClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def health( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[HealthResponse]: + """ + Check health of API and database + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[HealthResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/health", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + HealthResponse, + parse_obj_as( + type_=HealthResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 503: + raise ServiceUnavailableError(headers=dict(_response.headers)) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawHealthClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def health( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[HealthResponse]: + """ + Check health of API and database + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[HealthResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/health", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + HealthResponse, + parse_obj_as( + type_=HealthResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 503: + raise ServiceUnavailableError(headers=dict(_response.headers)) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/health/types/__init__.py b/langfuse/api/health/types/__init__.py new file mode 100644 index 000000000..d4bec6804 --- /dev/null +++ b/langfuse/api/health/types/__init__.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .health_response import HealthResponse +_dynamic_imports: typing.Dict[str, str] = {"HealthResponse": ".health_response"} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["HealthResponse"] diff --git a/langfuse/api/health/types/health_response.py b/langfuse/api/health/types/health_response.py new file mode 100644 index 000000000..b5bd855e5 --- /dev/null +++ b/langfuse/api/health/types/health_response.py @@ -0,0 +1,37 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class HealthResponse(UniversalBaseModel): + """ + Examples + -------- + from langfuse.health import HealthResponse + + HealthResponse( + version="1.25.0", + status="OK", + ) + """ + + version: str = pydantic.Field() + """ + Langfuse server version + """ + + status: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/__init__.py b/langfuse/api/ingestion/__init__.py new file mode 100644 index 000000000..5cd4ba3bd --- /dev/null +++ b/langfuse/api/ingestion/__init__.py @@ -0,0 +1,169 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + BaseEvent, + CreateEventBody, + CreateEventEvent, + CreateGenerationBody, + CreateGenerationEvent, + CreateObservationEvent, + CreateSpanBody, + CreateSpanEvent, + IngestionError, + IngestionEvent, + IngestionEvent_EventCreate, + IngestionEvent_GenerationCreate, + IngestionEvent_GenerationUpdate, + IngestionEvent_ObservationCreate, + IngestionEvent_ObservationUpdate, + IngestionEvent_ScoreCreate, + IngestionEvent_SdkLog, + IngestionEvent_SpanCreate, + IngestionEvent_SpanUpdate, + IngestionEvent_TraceCreate, + IngestionResponse, + IngestionSuccess, + IngestionUsage, + ObservationBody, + ObservationType, + OpenAiCompletionUsageSchema, + OpenAiResponseUsageSchema, + OpenAiUsage, + OptionalObservationBody, + ScoreBody, + ScoreEvent, + SdkLogBody, + SdkLogEvent, + TraceBody, + TraceEvent, + UpdateEventBody, + UpdateGenerationBody, + UpdateGenerationEvent, + UpdateObservationEvent, + UpdateSpanBody, + UpdateSpanEvent, + UsageDetails, + ) +_dynamic_imports: typing.Dict[str, str] = { + "BaseEvent": ".types", + "CreateEventBody": ".types", + "CreateEventEvent": ".types", + "CreateGenerationBody": ".types", + "CreateGenerationEvent": ".types", + "CreateObservationEvent": ".types", + "CreateSpanBody": ".types", + "CreateSpanEvent": ".types", + "IngestionError": ".types", + "IngestionEvent": ".types", + "IngestionEvent_EventCreate": ".types", + "IngestionEvent_GenerationCreate": ".types", + "IngestionEvent_GenerationUpdate": ".types", + "IngestionEvent_ObservationCreate": ".types", + "IngestionEvent_ObservationUpdate": ".types", + "IngestionEvent_ScoreCreate": ".types", + "IngestionEvent_SdkLog": ".types", + "IngestionEvent_SpanCreate": ".types", + "IngestionEvent_SpanUpdate": ".types", + "IngestionEvent_TraceCreate": ".types", + "IngestionResponse": ".types", + "IngestionSuccess": ".types", + "IngestionUsage": ".types", + "ObservationBody": ".types", + "ObservationType": ".types", + "OpenAiCompletionUsageSchema": ".types", + "OpenAiResponseUsageSchema": ".types", + "OpenAiUsage": ".types", + "OptionalObservationBody": ".types", + "ScoreBody": ".types", + "ScoreEvent": ".types", + "SdkLogBody": ".types", + "SdkLogEvent": ".types", + "TraceBody": ".types", + "TraceEvent": ".types", + "UpdateEventBody": ".types", + "UpdateGenerationBody": ".types", + "UpdateGenerationEvent": ".types", + "UpdateObservationEvent": ".types", + "UpdateSpanBody": ".types", + "UpdateSpanEvent": ".types", + "UsageDetails": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "BaseEvent", + "CreateEventBody", + "CreateEventEvent", + "CreateGenerationBody", + "CreateGenerationEvent", + "CreateObservationEvent", + "CreateSpanBody", + "CreateSpanEvent", + "IngestionError", + "IngestionEvent", + "IngestionEvent_EventCreate", + "IngestionEvent_GenerationCreate", + "IngestionEvent_GenerationUpdate", + "IngestionEvent_ObservationCreate", + "IngestionEvent_ObservationUpdate", + "IngestionEvent_ScoreCreate", + "IngestionEvent_SdkLog", + "IngestionEvent_SpanCreate", + "IngestionEvent_SpanUpdate", + "IngestionEvent_TraceCreate", + "IngestionResponse", + "IngestionSuccess", + "IngestionUsage", + "ObservationBody", + "ObservationType", + "OpenAiCompletionUsageSchema", + "OpenAiResponseUsageSchema", + "OpenAiUsage", + "OptionalObservationBody", + "ScoreBody", + "ScoreEvent", + "SdkLogBody", + "SdkLogEvent", + "TraceBody", + "TraceEvent", + "UpdateEventBody", + "UpdateGenerationBody", + "UpdateGenerationEvent", + "UpdateObservationEvent", + "UpdateSpanBody", + "UpdateSpanEvent", + "UsageDetails", +] diff --git a/langfuse/api/resources/ingestion/client.py b/langfuse/api/ingestion/client.py similarity index 64% rename from langfuse/api/resources/ingestion/client.py rename to langfuse/api/ingestion/client.py index c009c507b..af1da8396 100644 --- a/langfuse/api/resources/ingestion/client.py +++ b/langfuse/api/ingestion/client.py @@ -1,17 +1,10 @@ # This file was auto-generated by Fern from our API Definition. import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawIngestionClient, RawIngestionClient from .types.ingestion_event import IngestionEvent from .types.ingestion_response import IngestionResponse @@ -21,7 +14,18 @@ class IngestionClient: def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper + self._raw_client = RawIngestionClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawIngestionClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawIngestionClient + """ + return self._raw_client def batch( self, @@ -66,10 +70,10 @@ def batch( -------- import datetime - from langfuse import IngestionEvent_TraceCreate, TraceBody - from langfuse.client import FernLangfuse + from langfuse import LangfuseAPI + from langfuse.ingestion import IngestionEvent_TraceCreate, TraceBody - client = FernLangfuse( + client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -103,43 +107,26 @@ def batch( ], ) """ - _response = self._client_wrapper.httpx_client.request( - "api/public/ingestion", - method="POST", - json={"batch": batch, "metadata": metadata}, - request_options=request_options, - omit=OMIT, + _response = self._raw_client.batch( + batch=batch, metadata=metadata, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(IngestionResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data class AsyncIngestionClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper + self._raw_client = AsyncRawIngestionClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawIngestionClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawIngestionClient + """ + return self._raw_client async def batch( self, @@ -185,10 +172,10 @@ async def batch( import asyncio import datetime - from langfuse import IngestionEvent_TraceCreate, TraceBody - from langfuse.client import AsyncFernLangfuse + from langfuse import AsyncLangfuseAPI + from langfuse.ingestion import IngestionEvent_TraceCreate, TraceBody - client = AsyncFernLangfuse( + client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -228,35 +215,7 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/ingestion", - method="POST", - json={"batch": batch, "metadata": metadata}, - request_options=request_options, - omit=OMIT, + _response = await self._raw_client.batch( + batch=batch, metadata=metadata, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(IngestionResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data diff --git a/langfuse/api/ingestion/raw_client.py b/langfuse/api/ingestion/raw_client.py new file mode 100644 index 000000000..cb60a5fba --- /dev/null +++ b/langfuse/api/ingestion/raw_client.py @@ -0,0 +1,293 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from ..core.serialization import convert_and_respect_annotation_metadata +from .types.ingestion_event import IngestionEvent +from .types.ingestion_response import IngestionResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawIngestionClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def batch( + self, + *, + batch: typing.Sequence[IngestionEvent], + metadata: typing.Optional[typing.Any] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[IngestionResponse]: + """ + **Legacy endpoint for batch ingestion for Langfuse Observability.** + + -> Please use the OpenTelemetry endpoint (`/api/public/otel/v1/traces`). Learn more: https://langfuse.com/integrations/native/opentelemetry + + Within each batch, there can be multiple events. + Each event has a type, an id, a timestamp, metadata and a body. + Internally, we refer to this as the "event envelope" as it tells us something about the event but not the trace. + We use the event id within this envelope to deduplicate messages to avoid processing the same event twice, i.e. the event id should be unique per request. + The event.body.id is the ID of the actual trace and will be used for updates and will be visible within the Langfuse App. + I.e. if you want to update a trace, you'd use the same body id, but separate event IDs. + + Notes: + - Introduction to data model: https://langfuse.com/docs/observability/data-model + - Batch sizes are limited to 3.5 MB in total. You need to adjust the number of events per batch accordingly. + - The API does not return a 4xx status code for input errors. Instead, it responds with a 207 status code, which includes a list of the encountered errors. + + Parameters + ---------- + batch : typing.Sequence[IngestionEvent] + Batch of tracing events to be ingested. Discriminated by attribute `type`. + + metadata : typing.Optional[typing.Any] + Optional. Metadata field used by the Langfuse SDKs for debugging. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[IngestionResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/ingestion", + method="POST", + json={ + "batch": convert_and_respect_annotation_metadata( + object_=batch, + annotation=typing.Sequence[IngestionEvent], + direction="write", + ), + "metadata": metadata, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + IngestionResponse, + parse_obj_as( + type_=IngestionResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawIngestionClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def batch( + self, + *, + batch: typing.Sequence[IngestionEvent], + metadata: typing.Optional[typing.Any] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[IngestionResponse]: + """ + **Legacy endpoint for batch ingestion for Langfuse Observability.** + + -> Please use the OpenTelemetry endpoint (`/api/public/otel/v1/traces`). Learn more: https://langfuse.com/integrations/native/opentelemetry + + Within each batch, there can be multiple events. + Each event has a type, an id, a timestamp, metadata and a body. + Internally, we refer to this as the "event envelope" as it tells us something about the event but not the trace. + We use the event id within this envelope to deduplicate messages to avoid processing the same event twice, i.e. the event id should be unique per request. + The event.body.id is the ID of the actual trace and will be used for updates and will be visible within the Langfuse App. + I.e. if you want to update a trace, you'd use the same body id, but separate event IDs. + + Notes: + - Introduction to data model: https://langfuse.com/docs/observability/data-model + - Batch sizes are limited to 3.5 MB in total. You need to adjust the number of events per batch accordingly. + - The API does not return a 4xx status code for input errors. Instead, it responds with a 207 status code, which includes a list of the encountered errors. + + Parameters + ---------- + batch : typing.Sequence[IngestionEvent] + Batch of tracing events to be ingested. Discriminated by attribute `type`. + + metadata : typing.Optional[typing.Any] + Optional. Metadata field used by the Langfuse SDKs for debugging. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[IngestionResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/ingestion", + method="POST", + json={ + "batch": convert_and_respect_annotation_metadata( + object_=batch, + annotation=typing.Sequence[IngestionEvent], + direction="write", + ), + "metadata": metadata, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + IngestionResponse, + parse_obj_as( + type_=IngestionResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/ingestion/types/__init__.py b/langfuse/api/ingestion/types/__init__.py new file mode 100644 index 000000000..4addfd9c7 --- /dev/null +++ b/langfuse/api/ingestion/types/__init__.py @@ -0,0 +1,169 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .base_event import BaseEvent + from .create_event_body import CreateEventBody + from .create_event_event import CreateEventEvent + from .create_generation_body import CreateGenerationBody + from .create_generation_event import CreateGenerationEvent + from .create_observation_event import CreateObservationEvent + from .create_span_body import CreateSpanBody + from .create_span_event import CreateSpanEvent + from .ingestion_error import IngestionError + from .ingestion_event import ( + IngestionEvent, + IngestionEvent_EventCreate, + IngestionEvent_GenerationCreate, + IngestionEvent_GenerationUpdate, + IngestionEvent_ObservationCreate, + IngestionEvent_ObservationUpdate, + IngestionEvent_ScoreCreate, + IngestionEvent_SdkLog, + IngestionEvent_SpanCreate, + IngestionEvent_SpanUpdate, + IngestionEvent_TraceCreate, + ) + from .ingestion_response import IngestionResponse + from .ingestion_success import IngestionSuccess + from .ingestion_usage import IngestionUsage + from .observation_body import ObservationBody + from .observation_type import ObservationType + from .open_ai_completion_usage_schema import OpenAiCompletionUsageSchema + from .open_ai_response_usage_schema import OpenAiResponseUsageSchema + from .open_ai_usage import OpenAiUsage + from .optional_observation_body import OptionalObservationBody + from .score_body import ScoreBody + from .score_event import ScoreEvent + from .sdk_log_body import SdkLogBody + from .sdk_log_event import SdkLogEvent + from .trace_body import TraceBody + from .trace_event import TraceEvent + from .update_event_body import UpdateEventBody + from .update_generation_body import UpdateGenerationBody + from .update_generation_event import UpdateGenerationEvent + from .update_observation_event import UpdateObservationEvent + from .update_span_body import UpdateSpanBody + from .update_span_event import UpdateSpanEvent + from .usage_details import UsageDetails +_dynamic_imports: typing.Dict[str, str] = { + "BaseEvent": ".base_event", + "CreateEventBody": ".create_event_body", + "CreateEventEvent": ".create_event_event", + "CreateGenerationBody": ".create_generation_body", + "CreateGenerationEvent": ".create_generation_event", + "CreateObservationEvent": ".create_observation_event", + "CreateSpanBody": ".create_span_body", + "CreateSpanEvent": ".create_span_event", + "IngestionError": ".ingestion_error", + "IngestionEvent": ".ingestion_event", + "IngestionEvent_EventCreate": ".ingestion_event", + "IngestionEvent_GenerationCreate": ".ingestion_event", + "IngestionEvent_GenerationUpdate": ".ingestion_event", + "IngestionEvent_ObservationCreate": ".ingestion_event", + "IngestionEvent_ObservationUpdate": ".ingestion_event", + "IngestionEvent_ScoreCreate": ".ingestion_event", + "IngestionEvent_SdkLog": ".ingestion_event", + "IngestionEvent_SpanCreate": ".ingestion_event", + "IngestionEvent_SpanUpdate": ".ingestion_event", + "IngestionEvent_TraceCreate": ".ingestion_event", + "IngestionResponse": ".ingestion_response", + "IngestionSuccess": ".ingestion_success", + "IngestionUsage": ".ingestion_usage", + "ObservationBody": ".observation_body", + "ObservationType": ".observation_type", + "OpenAiCompletionUsageSchema": ".open_ai_completion_usage_schema", + "OpenAiResponseUsageSchema": ".open_ai_response_usage_schema", + "OpenAiUsage": ".open_ai_usage", + "OptionalObservationBody": ".optional_observation_body", + "ScoreBody": ".score_body", + "ScoreEvent": ".score_event", + "SdkLogBody": ".sdk_log_body", + "SdkLogEvent": ".sdk_log_event", + "TraceBody": ".trace_body", + "TraceEvent": ".trace_event", + "UpdateEventBody": ".update_event_body", + "UpdateGenerationBody": ".update_generation_body", + "UpdateGenerationEvent": ".update_generation_event", + "UpdateObservationEvent": ".update_observation_event", + "UpdateSpanBody": ".update_span_body", + "UpdateSpanEvent": ".update_span_event", + "UsageDetails": ".usage_details", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "BaseEvent", + "CreateEventBody", + "CreateEventEvent", + "CreateGenerationBody", + "CreateGenerationEvent", + "CreateObservationEvent", + "CreateSpanBody", + "CreateSpanEvent", + "IngestionError", + "IngestionEvent", + "IngestionEvent_EventCreate", + "IngestionEvent_GenerationCreate", + "IngestionEvent_GenerationUpdate", + "IngestionEvent_ObservationCreate", + "IngestionEvent_ObservationUpdate", + "IngestionEvent_ScoreCreate", + "IngestionEvent_SdkLog", + "IngestionEvent_SpanCreate", + "IngestionEvent_SpanUpdate", + "IngestionEvent_TraceCreate", + "IngestionResponse", + "IngestionSuccess", + "IngestionUsage", + "ObservationBody", + "ObservationType", + "OpenAiCompletionUsageSchema", + "OpenAiResponseUsageSchema", + "OpenAiUsage", + "OptionalObservationBody", + "ScoreBody", + "ScoreEvent", + "SdkLogBody", + "SdkLogEvent", + "TraceBody", + "TraceEvent", + "UpdateEventBody", + "UpdateGenerationBody", + "UpdateGenerationEvent", + "UpdateObservationEvent", + "UpdateSpanBody", + "UpdateSpanEvent", + "UsageDetails", +] diff --git a/langfuse/api/ingestion/types/base_event.py b/langfuse/api/ingestion/types/base_event.py new file mode 100644 index 000000000..5d94b2f3d --- /dev/null +++ b/langfuse/api/ingestion/types/base_event.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class BaseEvent(UniversalBaseModel): + id: str = pydantic.Field() + """ + UUID v4 that identifies the event + """ + + timestamp: str = pydantic.Field() + """ + Datetime (ISO 8601) of event creation in client. Should be as close to actual event creation in client as possible, this timestamp will be used for ordering of events in future release. Resolution: milliseconds (required), microseconds (optimal). + """ + + metadata: typing.Optional[typing.Any] = pydantic.Field(default=None) + """ + Optional. Metadata field used by the Langfuse SDKs for debugging. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/create_event_body.py b/langfuse/api/ingestion/types/create_event_body.py new file mode 100644 index 000000000..7de12e469 --- /dev/null +++ b/langfuse/api/ingestion/types/create_event_body.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .optional_observation_body import OptionalObservationBody + + +class CreateEventBody(OptionalObservationBody): + id: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/create_event_event.py b/langfuse/api/ingestion/types/create_event_event.py new file mode 100644 index 000000000..28212576c --- /dev/null +++ b/langfuse/api/ingestion/types/create_event_event.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_event import BaseEvent +from .create_event_body import CreateEventBody + + +class CreateEventEvent(BaseEvent): + body: CreateEventBody + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/create_generation_body.py b/langfuse/api/ingestion/types/create_generation_body.py new file mode 100644 index 000000000..288fe7031 --- /dev/null +++ b/langfuse/api/ingestion/types/create_generation_body.py @@ -0,0 +1,48 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...commons.types.map_value import MapValue +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .create_span_body import CreateSpanBody +from .ingestion_usage import IngestionUsage +from .usage_details import UsageDetails + + +class CreateGenerationBody(CreateSpanBody): + completion_start_time: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="completionStartTime") + ] = None + model: typing.Optional[str] = None + model_parameters: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, MapValue]], + FieldMetadata(alias="modelParameters"), + ] = None + usage: typing.Optional[IngestionUsage] = None + usage_details: typing_extensions.Annotated[ + typing.Optional[UsageDetails], FieldMetadata(alias="usageDetails") + ] = None + cost_details: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, float]], FieldMetadata(alias="costDetails") + ] = None + prompt_name: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="promptName") + ] = None + prompt_version: typing_extensions.Annotated[ + typing.Optional[int], FieldMetadata(alias="promptVersion") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/create_generation_event.py b/langfuse/api/ingestion/types/create_generation_event.py new file mode 100644 index 000000000..9ce73cda5 --- /dev/null +++ b/langfuse/api/ingestion/types/create_generation_event.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_event import BaseEvent +from .create_generation_body import CreateGenerationBody + + +class CreateGenerationEvent(BaseEvent): + body: CreateGenerationBody + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/create_observation_event.py b/langfuse/api/ingestion/types/create_observation_event.py new file mode 100644 index 000000000..7215907b3 --- /dev/null +++ b/langfuse/api/ingestion/types/create_observation_event.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_event import BaseEvent +from .observation_body import ObservationBody + + +class CreateObservationEvent(BaseEvent): + body: ObservationBody + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/create_span_body.py b/langfuse/api/ingestion/types/create_span_body.py new file mode 100644 index 000000000..2481da634 --- /dev/null +++ b/langfuse/api/ingestion/types/create_span_body.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .create_event_body import CreateEventBody + + +class CreateSpanBody(CreateEventBody): + end_time: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="endTime") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/create_span_event.py b/langfuse/api/ingestion/types/create_span_event.py new file mode 100644 index 000000000..dbd361f86 --- /dev/null +++ b/langfuse/api/ingestion/types/create_span_event.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_event import BaseEvent +from .create_span_body import CreateSpanBody + + +class CreateSpanEvent(BaseEvent): + body: CreateSpanBody + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/ingestion_error.py b/langfuse/api/ingestion/types/ingestion_error.py new file mode 100644 index 000000000..519cb368f --- /dev/null +++ b/langfuse/api/ingestion/types/ingestion_error.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class IngestionError(UniversalBaseModel): + id: str + status: int + message: typing.Optional[str] = None + error: typing.Optional[typing.Any] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/ingestion_event.py b/langfuse/api/ingestion/types/ingestion_event.py new file mode 100644 index 000000000..1cf2c5dc2 --- /dev/null +++ b/langfuse/api/ingestion/types/ingestion_event.py @@ -0,0 +1,225 @@ +# This file was auto-generated by Fern from our API Definition. + +from __future__ import annotations + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .create_event_body import CreateEventBody +from .create_generation_body import CreateGenerationBody +from .create_span_body import CreateSpanBody +from .observation_body import ObservationBody +from .score_body import ScoreBody +from .sdk_log_body import SdkLogBody +from .trace_body import TraceBody +from .update_generation_body import UpdateGenerationBody +from .update_span_body import UpdateSpanBody + + +class IngestionEvent_TraceCreate(UniversalBaseModel): + type: typing.Literal["trace-create"] = "trace-create" + body: TraceBody + id: str + timestamp: str + metadata: typing.Optional[typing.Any] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class IngestionEvent_ScoreCreate(UniversalBaseModel): + type: typing.Literal["score-create"] = "score-create" + body: ScoreBody + id: str + timestamp: str + metadata: typing.Optional[typing.Any] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class IngestionEvent_SpanCreate(UniversalBaseModel): + type: typing.Literal["span-create"] = "span-create" + body: CreateSpanBody + id: str + timestamp: str + metadata: typing.Optional[typing.Any] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class IngestionEvent_SpanUpdate(UniversalBaseModel): + type: typing.Literal["span-update"] = "span-update" + body: UpdateSpanBody + id: str + timestamp: str + metadata: typing.Optional[typing.Any] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class IngestionEvent_GenerationCreate(UniversalBaseModel): + type: typing.Literal["generation-create"] = "generation-create" + body: CreateGenerationBody + id: str + timestamp: str + metadata: typing.Optional[typing.Any] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class IngestionEvent_GenerationUpdate(UniversalBaseModel): + type: typing.Literal["generation-update"] = "generation-update" + body: UpdateGenerationBody + id: str + timestamp: str + metadata: typing.Optional[typing.Any] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class IngestionEvent_EventCreate(UniversalBaseModel): + type: typing.Literal["event-create"] = "event-create" + body: CreateEventBody + id: str + timestamp: str + metadata: typing.Optional[typing.Any] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class IngestionEvent_SdkLog(UniversalBaseModel): + type: typing.Literal["sdk-log"] = "sdk-log" + body: SdkLogBody + id: str + timestamp: str + metadata: typing.Optional[typing.Any] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class IngestionEvent_ObservationCreate(UniversalBaseModel): + type: typing.Literal["observation-create"] = "observation-create" + body: ObservationBody + id: str + timestamp: str + metadata: typing.Optional[typing.Any] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class IngestionEvent_ObservationUpdate(UniversalBaseModel): + type: typing.Literal["observation-update"] = "observation-update" + body: ObservationBody + id: str + timestamp: str + metadata: typing.Optional[typing.Any] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +IngestionEvent = typing_extensions.Annotated[ + typing.Union[ + IngestionEvent_TraceCreate, + IngestionEvent_ScoreCreate, + IngestionEvent_SpanCreate, + IngestionEvent_SpanUpdate, + IngestionEvent_GenerationCreate, + IngestionEvent_GenerationUpdate, + IngestionEvent_EventCreate, + IngestionEvent_SdkLog, + IngestionEvent_ObservationCreate, + IngestionEvent_ObservationUpdate, + ], + pydantic.Field(discriminator="type"), +] diff --git a/langfuse/api/ingestion/types/ingestion_response.py b/langfuse/api/ingestion/types/ingestion_response.py new file mode 100644 index 000000000..dfad21d75 --- /dev/null +++ b/langfuse/api/ingestion/types/ingestion_response.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .ingestion_error import IngestionError +from .ingestion_success import IngestionSuccess + + +class IngestionResponse(UniversalBaseModel): + successes: typing.List[IngestionSuccess] + errors: typing.List[IngestionError] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/ingestion_success.py b/langfuse/api/ingestion/types/ingestion_success.py new file mode 100644 index 000000000..5afed80c9 --- /dev/null +++ b/langfuse/api/ingestion/types/ingestion_success.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class IngestionSuccess(UniversalBaseModel): + id: str + status: int + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/resources/ingestion/types/ingestion_usage.py b/langfuse/api/ingestion/types/ingestion_usage.py similarity index 100% rename from langfuse/api/resources/ingestion/types/ingestion_usage.py rename to langfuse/api/ingestion/types/ingestion_usage.py diff --git a/langfuse/api/ingestion/types/observation_body.py b/langfuse/api/ingestion/types/observation_body.py new file mode 100644 index 000000000..32302863c --- /dev/null +++ b/langfuse/api/ingestion/types/observation_body.py @@ -0,0 +1,60 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...commons.types.map_value import MapValue +from ...commons.types.observation_level import ObservationLevel +from ...commons.types.usage import Usage +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .observation_type import ObservationType + + +class ObservationBody(UniversalBaseModel): + id: typing.Optional[str] = None + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = None + type: ObservationType + name: typing.Optional[str] = None + start_time: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="startTime") + ] = None + end_time: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="endTime") + ] = None + completion_start_time: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="completionStartTime") + ] = None + model: typing.Optional[str] = None + model_parameters: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, MapValue]], + FieldMetadata(alias="modelParameters"), + ] = None + input: typing.Optional[typing.Any] = None + version: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + output: typing.Optional[typing.Any] = None + usage: typing.Optional[Usage] = None + level: typing.Optional[ObservationLevel] = None + status_message: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="statusMessage") + ] = None + parent_observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="parentObservationId") + ] = None + environment: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/observation_type.py b/langfuse/api/ingestion/types/observation_type.py new file mode 100644 index 000000000..eb6079ba7 --- /dev/null +++ b/langfuse/api/ingestion/types/observation_type.py @@ -0,0 +1,19 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +ObservationType = typing.Union[ + typing.Literal[ + "SPAN", + "GENERATION", + "EVENT", + "AGENT", + "TOOL", + "CHAIN", + "RETRIEVER", + "EVALUATOR", + "EMBEDDING", + "GUARDRAIL", + ], + typing.Any, +] diff --git a/langfuse/api/ingestion/types/open_ai_completion_usage_schema.py b/langfuse/api/ingestion/types/open_ai_completion_usage_schema.py new file mode 100644 index 000000000..b051f25c5 --- /dev/null +++ b/langfuse/api/ingestion/types/open_ai_completion_usage_schema.py @@ -0,0 +1,33 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class OpenAiCompletionUsageSchema(UniversalBaseModel): + """ + OpenAI Usage schema from (Chat-)Completion APIs + """ + + prompt_tokens: int + completion_tokens: int + total_tokens: int + prompt_tokens_details: typing.Optional[typing.Dict[str, typing.Optional[int]]] = ( + None + ) + completion_tokens_details: typing.Optional[ + typing.Dict[str, typing.Optional[int]] + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/open_ai_response_usage_schema.py b/langfuse/api/ingestion/types/open_ai_response_usage_schema.py new file mode 100644 index 000000000..1728aaae4 --- /dev/null +++ b/langfuse/api/ingestion/types/open_ai_response_usage_schema.py @@ -0,0 +1,31 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class OpenAiResponseUsageSchema(UniversalBaseModel): + """ + OpenAI Usage schema from Response API + """ + + input_tokens: int + output_tokens: int + total_tokens: int + input_tokens_details: typing.Optional[typing.Dict[str, typing.Optional[int]]] = None + output_tokens_details: typing.Optional[typing.Dict[str, typing.Optional[int]]] = ( + None + ) + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/open_ai_usage.py b/langfuse/api/ingestion/types/open_ai_usage.py new file mode 100644 index 000000000..254ef2281 --- /dev/null +++ b/langfuse/api/ingestion/types/open_ai_usage.py @@ -0,0 +1,35 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class OpenAiUsage(UniversalBaseModel): + """ + Usage interface of OpenAI for improved compatibility. + """ + + prompt_tokens: typing_extensions.Annotated[ + typing.Optional[int], FieldMetadata(alias="promptTokens") + ] = None + completion_tokens: typing_extensions.Annotated[ + typing.Optional[int], FieldMetadata(alias="completionTokens") + ] = None + total_tokens: typing_extensions.Annotated[ + typing.Optional[int], FieldMetadata(alias="totalTokens") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/optional_observation_body.py b/langfuse/api/ingestion/types/optional_observation_body.py new file mode 100644 index 000000000..9422c0c2d --- /dev/null +++ b/langfuse/api/ingestion/types/optional_observation_body.py @@ -0,0 +1,43 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...commons.types.observation_level import ObservationLevel +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class OptionalObservationBody(UniversalBaseModel): + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = None + name: typing.Optional[str] = None + start_time: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="startTime") + ] = None + metadata: typing.Optional[typing.Any] = None + input: typing.Optional[typing.Any] = None + output: typing.Optional[typing.Any] = None + level: typing.Optional[ObservationLevel] = None + status_message: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="statusMessage") + ] = None + parent_observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="parentObservationId") + ] = None + version: typing.Optional[str] = None + environment: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/score_body.py b/langfuse/api/ingestion/types/score_body.py new file mode 100644 index 000000000..dd52ed301 --- /dev/null +++ b/langfuse/api/ingestion/types/score_body.py @@ -0,0 +1,78 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...commons.types.create_score_value import CreateScoreValue +from ...commons.types.score_data_type import ScoreDataType +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class ScoreBody(UniversalBaseModel): + """ + Examples + -------- + from langfuse.ingestion import ScoreBody + + ScoreBody( + name="novelty", + value=0.9, + trace_id="cdef-1234-5678-90ab", + ) + """ + + id: typing.Optional[str] = None + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = None + session_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sessionId") + ] = None + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + dataset_run_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="datasetRunId") + ] = None + name: str + environment: typing.Optional[str] = None + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = pydantic.Field(default=None) + """ + The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. + """ + + value: CreateScoreValue = pydantic.Field() + """ + The value of the score. Must be passed as string for categorical scores, and numeric for boolean and numeric scores. Boolean score values must equal either 1 or 0 (true or false) + """ + + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + data_type: typing_extensions.Annotated[ + typing.Optional[ScoreDataType], FieldMetadata(alias="dataType") + ] = pydantic.Field(default=None) + """ + When set, must match the score value's type. If not set, will be inferred from the score value or config + """ + + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = pydantic.Field(default=None) + """ + Reference a score config on a score. When set, the score name must equal the config name and scores must comply with the config's range and data type. For categorical scores, the value must map to a config category. Numeric scores might be constrained by the score config's max and min values + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/score_event.py b/langfuse/api/ingestion/types/score_event.py new file mode 100644 index 000000000..e7ffe9f6c --- /dev/null +++ b/langfuse/api/ingestion/types/score_event.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_event import BaseEvent +from .score_body import ScoreBody + + +class ScoreEvent(BaseEvent): + body: ScoreBody + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/sdk_log_body.py b/langfuse/api/ingestion/types/sdk_log_body.py new file mode 100644 index 000000000..46fe0ca0f --- /dev/null +++ b/langfuse/api/ingestion/types/sdk_log_body.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class SdkLogBody(UniversalBaseModel): + log: typing.Any + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/sdk_log_event.py b/langfuse/api/ingestion/types/sdk_log_event.py new file mode 100644 index 000000000..0a3e15105 --- /dev/null +++ b/langfuse/api/ingestion/types/sdk_log_event.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_event import BaseEvent +from .sdk_log_body import SdkLogBody + + +class SdkLogEvent(BaseEvent): + body: SdkLogBody + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/trace_body.py b/langfuse/api/ingestion/types/trace_body.py new file mode 100644 index 000000000..3b108a8b5 --- /dev/null +++ b/langfuse/api/ingestion/types/trace_body.py @@ -0,0 +1,43 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class TraceBody(UniversalBaseModel): + id: typing.Optional[str] = None + timestamp: typing.Optional[dt.datetime] = None + name: typing.Optional[str] = None + user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="userId") + ] = None + input: typing.Optional[typing.Any] = None + output: typing.Optional[typing.Any] = None + session_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sessionId") + ] = None + release: typing.Optional[str] = None + version: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + tags: typing.Optional[typing.List[str]] = None + environment: typing.Optional[str] = None + public: typing.Optional[bool] = pydantic.Field(default=None) + """ + Make trace publicly accessible via url + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/trace_event.py b/langfuse/api/ingestion/types/trace_event.py new file mode 100644 index 000000000..89adfa241 --- /dev/null +++ b/langfuse/api/ingestion/types/trace_event.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_event import BaseEvent +from .trace_body import TraceBody + + +class TraceEvent(BaseEvent): + body: TraceBody + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/update_event_body.py b/langfuse/api/ingestion/types/update_event_body.py new file mode 100644 index 000000000..0973d8517 --- /dev/null +++ b/langfuse/api/ingestion/types/update_event_body.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .optional_observation_body import OptionalObservationBody + + +class UpdateEventBody(OptionalObservationBody): + id: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/update_generation_body.py b/langfuse/api/ingestion/types/update_generation_body.py new file mode 100644 index 000000000..c1a677385 --- /dev/null +++ b/langfuse/api/ingestion/types/update_generation_body.py @@ -0,0 +1,48 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...commons.types.map_value import MapValue +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .ingestion_usage import IngestionUsage +from .update_span_body import UpdateSpanBody +from .usage_details import UsageDetails + + +class UpdateGenerationBody(UpdateSpanBody): + completion_start_time: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="completionStartTime") + ] = None + model: typing.Optional[str] = None + model_parameters: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, MapValue]], + FieldMetadata(alias="modelParameters"), + ] = None + usage: typing.Optional[IngestionUsage] = None + prompt_name: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="promptName") + ] = None + usage_details: typing_extensions.Annotated[ + typing.Optional[UsageDetails], FieldMetadata(alias="usageDetails") + ] = None + cost_details: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, float]], FieldMetadata(alias="costDetails") + ] = None + prompt_version: typing_extensions.Annotated[ + typing.Optional[int], FieldMetadata(alias="promptVersion") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/update_generation_event.py b/langfuse/api/ingestion/types/update_generation_event.py new file mode 100644 index 000000000..d1978fd13 --- /dev/null +++ b/langfuse/api/ingestion/types/update_generation_event.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_event import BaseEvent +from .update_generation_body import UpdateGenerationBody + + +class UpdateGenerationEvent(BaseEvent): + body: UpdateGenerationBody + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/update_observation_event.py b/langfuse/api/ingestion/types/update_observation_event.py new file mode 100644 index 000000000..0e8f349ac --- /dev/null +++ b/langfuse/api/ingestion/types/update_observation_event.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_event import BaseEvent +from .observation_body import ObservationBody + + +class UpdateObservationEvent(BaseEvent): + body: ObservationBody + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/update_span_body.py b/langfuse/api/ingestion/types/update_span_body.py new file mode 100644 index 000000000..745460221 --- /dev/null +++ b/langfuse/api/ingestion/types/update_span_body.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from ...core.serialization import FieldMetadata +from .update_event_body import UpdateEventBody + + +class UpdateSpanBody(UpdateEventBody): + end_time: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="endTime") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/ingestion/types/update_span_event.py b/langfuse/api/ingestion/types/update_span_event.py new file mode 100644 index 000000000..63dbc6c53 --- /dev/null +++ b/langfuse/api/ingestion/types/update_span_event.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_event import BaseEvent +from .update_span_body import UpdateSpanBody + + +class UpdateSpanEvent(BaseEvent): + body: UpdateSpanBody + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/resources/ingestion/types/usage_details.py b/langfuse/api/ingestion/types/usage_details.py similarity index 100% rename from langfuse/api/resources/ingestion/types/usage_details.py rename to langfuse/api/ingestion/types/usage_details.py diff --git a/langfuse/api/llm_connections/__init__.py b/langfuse/api/llm_connections/__init__.py new file mode 100644 index 000000000..aba7157f1 --- /dev/null +++ b/langfuse/api/llm_connections/__init__.py @@ -0,0 +1,55 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + LlmAdapter, + LlmConnection, + PaginatedLlmConnections, + UpsertLlmConnectionRequest, + ) +_dynamic_imports: typing.Dict[str, str] = { + "LlmAdapter": ".types", + "LlmConnection": ".types", + "PaginatedLlmConnections": ".types", + "UpsertLlmConnectionRequest": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "LlmAdapter", + "LlmConnection", + "PaginatedLlmConnections", + "UpsertLlmConnectionRequest", +] diff --git a/langfuse/api/llm_connections/client.py b/langfuse/api/llm_connections/client.py new file mode 100644 index 000000000..5fcc6b8a7 --- /dev/null +++ b/langfuse/api/llm_connections/client.py @@ -0,0 +1,309 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawLlmConnectionsClient, RawLlmConnectionsClient +from .types.llm_adapter import LlmAdapter +from .types.llm_connection import LlmConnection +from .types.paginated_llm_connections import PaginatedLlmConnections + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class LlmConnectionsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawLlmConnectionsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawLlmConnectionsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawLlmConnectionsClient + """ + return self._raw_client + + def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedLlmConnections: + """ + Get all LLM connections in a project + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedLlmConnections + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.llm_connections.list() + """ + _response = self._raw_client.list( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + def upsert( + self, + *, + provider: str, + adapter: LlmAdapter, + secret_key: str, + base_url: typing.Optional[str] = OMIT, + custom_models: typing.Optional[typing.Sequence[str]] = OMIT, + with_default_models: typing.Optional[bool] = OMIT, + extra_headers: typing.Optional[typing.Dict[str, str]] = OMIT, + config: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> LlmConnection: + """ + Create or update an LLM connection. The connection is upserted on provider. + + Parameters + ---------- + provider : str + Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. + + adapter : LlmAdapter + The adapter used to interface with the LLM + + secret_key : str + Secret key for the LLM API. + + base_url : typing.Optional[str] + Custom base URL for the LLM API + + custom_models : typing.Optional[typing.Sequence[str]] + List of custom model names + + with_default_models : typing.Optional[bool] + Whether to include default models. Default is true. + + extra_headers : typing.Optional[typing.Dict[str, str]] + Extra headers to send with requests + + config : typing.Optional[typing.Dict[str, typing.Any]] + Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": ""}` (e.g., `{"region":"us-east-1"}`) - **VertexAI**: Optional. If provided, must be `{"location": ""}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + LlmConnection + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.llm_connections.upsert( + provider="provider", + adapter="anthropic", + secret_key="secretKey", + ) + """ + _response = self._raw_client.upsert( + provider=provider, + adapter=adapter, + secret_key=secret_key, + base_url=base_url, + custom_models=custom_models, + with_default_models=with_default_models, + extra_headers=extra_headers, + config=config, + request_options=request_options, + ) + return _response.data + + +class AsyncLlmConnectionsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawLlmConnectionsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawLlmConnectionsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawLlmConnectionsClient + """ + return self._raw_client + + async def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedLlmConnections: + """ + Get all LLM connections in a project + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedLlmConnections + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.llm_connections.list() + + + asyncio.run(main()) + """ + _response = await self._raw_client.list( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + async def upsert( + self, + *, + provider: str, + adapter: LlmAdapter, + secret_key: str, + base_url: typing.Optional[str] = OMIT, + custom_models: typing.Optional[typing.Sequence[str]] = OMIT, + with_default_models: typing.Optional[bool] = OMIT, + extra_headers: typing.Optional[typing.Dict[str, str]] = OMIT, + config: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> LlmConnection: + """ + Create or update an LLM connection. The connection is upserted on provider. + + Parameters + ---------- + provider : str + Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. + + adapter : LlmAdapter + The adapter used to interface with the LLM + + secret_key : str + Secret key for the LLM API. + + base_url : typing.Optional[str] + Custom base URL for the LLM API + + custom_models : typing.Optional[typing.Sequence[str]] + List of custom model names + + with_default_models : typing.Optional[bool] + Whether to include default models. Default is true. + + extra_headers : typing.Optional[typing.Dict[str, str]] + Extra headers to send with requests + + config : typing.Optional[typing.Dict[str, typing.Any]] + Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": ""}` (e.g., `{"region":"us-east-1"}`) - **VertexAI**: Optional. If provided, must be `{"location": ""}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + LlmConnection + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.llm_connections.upsert( + provider="provider", + adapter="anthropic", + secret_key="secretKey", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.upsert( + provider=provider, + adapter=adapter, + secret_key=secret_key, + base_url=base_url, + custom_models=custom_models, + with_default_models=with_default_models, + extra_headers=extra_headers, + config=config, + request_options=request_options, + ) + return _response.data diff --git a/langfuse/api/llm_connections/raw_client.py b/langfuse/api/llm_connections/raw_client.py new file mode 100644 index 000000000..ef4f87425 --- /dev/null +++ b/langfuse/api/llm_connections/raw_client.py @@ -0,0 +1,541 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.llm_adapter import LlmAdapter +from .types.llm_connection import LlmConnection +from .types.paginated_llm_connections import PaginatedLlmConnections + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawLlmConnectionsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[PaginatedLlmConnections]: + """ + Get all LLM connections in a project + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[PaginatedLlmConnections] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/llm-connections", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedLlmConnections, + parse_obj_as( + type_=PaginatedLlmConnections, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def upsert( + self, + *, + provider: str, + adapter: LlmAdapter, + secret_key: str, + base_url: typing.Optional[str] = OMIT, + custom_models: typing.Optional[typing.Sequence[str]] = OMIT, + with_default_models: typing.Optional[bool] = OMIT, + extra_headers: typing.Optional[typing.Dict[str, str]] = OMIT, + config: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[LlmConnection]: + """ + Create or update an LLM connection. The connection is upserted on provider. + + Parameters + ---------- + provider : str + Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. + + adapter : LlmAdapter + The adapter used to interface with the LLM + + secret_key : str + Secret key for the LLM API. + + base_url : typing.Optional[str] + Custom base URL for the LLM API + + custom_models : typing.Optional[typing.Sequence[str]] + List of custom model names + + with_default_models : typing.Optional[bool] + Whether to include default models. Default is true. + + extra_headers : typing.Optional[typing.Dict[str, str]] + Extra headers to send with requests + + config : typing.Optional[typing.Dict[str, typing.Any]] + Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": ""}` (e.g., `{"region":"us-east-1"}`) - **VertexAI**: Optional. If provided, must be `{"location": ""}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[LlmConnection] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/llm-connections", + method="PUT", + json={ + "provider": provider, + "adapter": adapter, + "secretKey": secret_key, + "baseURL": base_url, + "customModels": custom_models, + "withDefaultModels": with_default_models, + "extraHeaders": extra_headers, + "config": config, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + LlmConnection, + parse_obj_as( + type_=LlmConnection, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawLlmConnectionsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[PaginatedLlmConnections]: + """ + Get all LLM connections in a project + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[PaginatedLlmConnections] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/llm-connections", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedLlmConnections, + parse_obj_as( + type_=PaginatedLlmConnections, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def upsert( + self, + *, + provider: str, + adapter: LlmAdapter, + secret_key: str, + base_url: typing.Optional[str] = OMIT, + custom_models: typing.Optional[typing.Sequence[str]] = OMIT, + with_default_models: typing.Optional[bool] = OMIT, + extra_headers: typing.Optional[typing.Dict[str, str]] = OMIT, + config: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[LlmConnection]: + """ + Create or update an LLM connection. The connection is upserted on provider. + + Parameters + ---------- + provider : str + Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. + + adapter : LlmAdapter + The adapter used to interface with the LLM + + secret_key : str + Secret key for the LLM API. + + base_url : typing.Optional[str] + Custom base URL for the LLM API + + custom_models : typing.Optional[typing.Sequence[str]] + List of custom model names + + with_default_models : typing.Optional[bool] + Whether to include default models. Default is true. + + extra_headers : typing.Optional[typing.Dict[str, str]] + Extra headers to send with requests + + config : typing.Optional[typing.Dict[str, typing.Any]] + Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": ""}` (e.g., `{"region":"us-east-1"}`) - **VertexAI**: Optional. If provided, must be `{"location": ""}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[LlmConnection] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/llm-connections", + method="PUT", + json={ + "provider": provider, + "adapter": adapter, + "secretKey": secret_key, + "baseURL": base_url, + "customModels": custom_models, + "withDefaultModels": with_default_models, + "extraHeaders": extra_headers, + "config": config, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + LlmConnection, + parse_obj_as( + type_=LlmConnection, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/llm_connections/types/__init__.py b/langfuse/api/llm_connections/types/__init__.py new file mode 100644 index 000000000..e6ba89200 --- /dev/null +++ b/langfuse/api/llm_connections/types/__init__.py @@ -0,0 +1,53 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .llm_adapter import LlmAdapter + from .llm_connection import LlmConnection + from .paginated_llm_connections import PaginatedLlmConnections + from .upsert_llm_connection_request import UpsertLlmConnectionRequest +_dynamic_imports: typing.Dict[str, str] = { + "LlmAdapter": ".llm_adapter", + "LlmConnection": ".llm_connection", + "PaginatedLlmConnections": ".paginated_llm_connections", + "UpsertLlmConnectionRequest": ".upsert_llm_connection_request", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "LlmAdapter", + "LlmConnection", + "PaginatedLlmConnections", + "UpsertLlmConnectionRequest", +] diff --git a/langfuse/api/llm_connections/types/llm_adapter.py b/langfuse/api/llm_connections/types/llm_adapter.py new file mode 100644 index 000000000..51470bf1d --- /dev/null +++ b/langfuse/api/llm_connections/types/llm_adapter.py @@ -0,0 +1,15 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +LlmAdapter = typing.Union[ + typing.Literal[ + "anthropic", + "openai", + "azure", + "bedrock", + "google-vertex-ai", + "google-ai-studio", + ], + typing.Any, +] diff --git a/langfuse/api/llm_connections/types/llm_connection.py b/langfuse/api/llm_connections/types/llm_connection.py new file mode 100644 index 000000000..8f147b33f --- /dev/null +++ b/langfuse/api/llm_connections/types/llm_connection.py @@ -0,0 +1,84 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class LlmConnection(UniversalBaseModel): + """ + LLM API connection configuration (secrets excluded) + """ + + id: str + provider: str = pydantic.Field() + """ + Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. + """ + + adapter: str = pydantic.Field() + """ + The adapter used to interface with the LLM + """ + + display_secret_key: typing_extensions.Annotated[ + str, FieldMetadata(alias="displaySecretKey") + ] = pydantic.Field() + """ + Masked version of the secret key for display purposes + """ + + base_url: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="baseURL") + ] = pydantic.Field(default=None) + """ + Custom base URL for the LLM API + """ + + custom_models: typing_extensions.Annotated[ + typing.List[str], FieldMetadata(alias="customModels") + ] = pydantic.Field() + """ + List of custom model names available for this connection + """ + + with_default_models: typing_extensions.Annotated[ + bool, FieldMetadata(alias="withDefaultModels") + ] = pydantic.Field() + """ + Whether to include default models for this adapter + """ + + extra_header_keys: typing_extensions.Annotated[ + typing.List[str], FieldMetadata(alias="extraHeaderKeys") + ] = pydantic.Field() + """ + Keys of extra headers sent with requests (values excluded for security) + """ + + config: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(default=None) + """ + Adapter-specific configuration. Required for Bedrock (`{"region":"us-east-1"}`), optional for VertexAI (`{"location":"us-central1"}`), not used by other adapters. + """ + + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/llm_connections/types/paginated_llm_connections.py b/langfuse/api/llm_connections/types/paginated_llm_connections.py new file mode 100644 index 000000000..d0db0b14d --- /dev/null +++ b/langfuse/api/llm_connections/types/paginated_llm_connections.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse +from .llm_connection import LlmConnection + + +class PaginatedLlmConnections(UniversalBaseModel): + data: typing.List[LlmConnection] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/llm_connections/types/upsert_llm_connection_request.py b/langfuse/api/llm_connections/types/upsert_llm_connection_request.py new file mode 100644 index 000000000..1ba5cfa49 --- /dev/null +++ b/langfuse/api/llm_connections/types/upsert_llm_connection_request.py @@ -0,0 +1,76 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .llm_adapter import LlmAdapter + + +class UpsertLlmConnectionRequest(UniversalBaseModel): + """ + Request to create or update an LLM connection (upsert) + """ + + provider: str = pydantic.Field() + """ + Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. + """ + + adapter: LlmAdapter = pydantic.Field() + """ + The adapter used to interface with the LLM + """ + + secret_key: typing_extensions.Annotated[str, FieldMetadata(alias="secretKey")] = ( + pydantic.Field() + ) + """ + Secret key for the LLM API. + """ + + base_url: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="baseURL") + ] = pydantic.Field(default=None) + """ + Custom base URL for the LLM API + """ + + custom_models: typing_extensions.Annotated[ + typing.Optional[typing.List[str]], FieldMetadata(alias="customModels") + ] = pydantic.Field(default=None) + """ + List of custom model names + """ + + with_default_models: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="withDefaultModels") + ] = pydantic.Field(default=None) + """ + Whether to include default models. Default is true. + """ + + extra_headers: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, str]], FieldMetadata(alias="extraHeaders") + ] = pydantic.Field(default=None) + """ + Extra headers to send with requests + """ + + config: typing.Optional[typing.Dict[str, typing.Any]] = pydantic.Field(default=None) + """ + Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": ""}` (e.g., `{"region":"us-east-1"}`) - **VertexAI**: Optional. If provided, must be `{"location": ""}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/media/__init__.py b/langfuse/api/media/__init__.py new file mode 100644 index 000000000..85d8f7b4f --- /dev/null +++ b/langfuse/api/media/__init__.py @@ -0,0 +1,58 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + GetMediaResponse, + GetMediaUploadUrlRequest, + GetMediaUploadUrlResponse, + MediaContentType, + PatchMediaBody, + ) +_dynamic_imports: typing.Dict[str, str] = { + "GetMediaResponse": ".types", + "GetMediaUploadUrlRequest": ".types", + "GetMediaUploadUrlResponse": ".types", + "MediaContentType": ".types", + "PatchMediaBody": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "GetMediaResponse", + "GetMediaUploadUrlRequest", + "GetMediaUploadUrlResponse", + "MediaContentType", + "PatchMediaBody", +] diff --git a/langfuse/api/media/client.py b/langfuse/api/media/client.py new file mode 100644 index 000000000..3665a9366 --- /dev/null +++ b/langfuse/api/media/client.py @@ -0,0 +1,425 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawMediaClient, RawMediaClient +from .types.get_media_response import GetMediaResponse +from .types.get_media_upload_url_response import GetMediaUploadUrlResponse +from .types.media_content_type import MediaContentType + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class MediaClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawMediaClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawMediaClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawMediaClient + """ + return self._raw_client + + def get( + self, media_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> GetMediaResponse: + """ + Get a media record + + Parameters + ---------- + media_id : str + The unique langfuse identifier of a media record + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetMediaResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.media.get( + media_id="mediaId", + ) + """ + _response = self._raw_client.get(media_id, request_options=request_options) + return _response.data + + def patch( + self, + media_id: str, + *, + uploaded_at: dt.datetime, + upload_http_status: int, + upload_http_error: typing.Optional[str] = OMIT, + upload_time_ms: typing.Optional[int] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Patch a media record + + Parameters + ---------- + media_id : str + The unique langfuse identifier of a media record + + uploaded_at : dt.datetime + The date and time when the media record was uploaded + + upload_http_status : int + The HTTP status code of the upload + + upload_http_error : typing.Optional[str] + The HTTP error message of the upload + + upload_time_ms : typing.Optional[int] + The time in milliseconds it took to upload the media record + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import datetime + + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.media.patch( + media_id="mediaId", + uploaded_at=datetime.datetime.fromisoformat( + "2024-01-15 09:30:00+00:00", + ), + upload_http_status=1, + ) + """ + _response = self._raw_client.patch( + media_id, + uploaded_at=uploaded_at, + upload_http_status=upload_http_status, + upload_http_error=upload_http_error, + upload_time_ms=upload_time_ms, + request_options=request_options, + ) + return _response.data + + def get_upload_url( + self, + *, + trace_id: str, + content_type: MediaContentType, + content_length: int, + sha256hash: str, + field: str, + observation_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> GetMediaUploadUrlResponse: + """ + Get a presigned upload URL for a media record + + Parameters + ---------- + trace_id : str + The trace ID associated with the media record + + content_type : MediaContentType + + content_length : int + The size of the media record in bytes + + sha256hash : str + The SHA-256 hash of the media record + + field : str + The trace / observation field the media record is associated with. This can be one of `input`, `output`, `metadata` + + observation_id : typing.Optional[str] + The observation ID associated with the media record. If the media record is associated directly with a trace, this will be null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetMediaUploadUrlResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.media.get_upload_url( + trace_id="traceId", + content_type="image/png", + content_length=1, + sha256hash="sha256Hash", + field="field", + ) + """ + _response = self._raw_client.get_upload_url( + trace_id=trace_id, + content_type=content_type, + content_length=content_length, + sha256hash=sha256hash, + field=field, + observation_id=observation_id, + request_options=request_options, + ) + return _response.data + + +class AsyncMediaClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawMediaClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawMediaClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawMediaClient + """ + return self._raw_client + + async def get( + self, media_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> GetMediaResponse: + """ + Get a media record + + Parameters + ---------- + media_id : str + The unique langfuse identifier of a media record + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetMediaResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.media.get( + media_id="mediaId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get( + media_id, request_options=request_options + ) + return _response.data + + async def patch( + self, + media_id: str, + *, + uploaded_at: dt.datetime, + upload_http_status: int, + upload_http_error: typing.Optional[str] = OMIT, + upload_time_ms: typing.Optional[int] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Patch a media record + + Parameters + ---------- + media_id : str + The unique langfuse identifier of a media record + + uploaded_at : dt.datetime + The date and time when the media record was uploaded + + upload_http_status : int + The HTTP status code of the upload + + upload_http_error : typing.Optional[str] + The HTTP error message of the upload + + upload_time_ms : typing.Optional[int] + The time in milliseconds it took to upload the media record + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import asyncio + import datetime + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.media.patch( + media_id="mediaId", + uploaded_at=datetime.datetime.fromisoformat( + "2024-01-15 09:30:00+00:00", + ), + upload_http_status=1, + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.patch( + media_id, + uploaded_at=uploaded_at, + upload_http_status=upload_http_status, + upload_http_error=upload_http_error, + upload_time_ms=upload_time_ms, + request_options=request_options, + ) + return _response.data + + async def get_upload_url( + self, + *, + trace_id: str, + content_type: MediaContentType, + content_length: int, + sha256hash: str, + field: str, + observation_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> GetMediaUploadUrlResponse: + """ + Get a presigned upload URL for a media record + + Parameters + ---------- + trace_id : str + The trace ID associated with the media record + + content_type : MediaContentType + + content_length : int + The size of the media record in bytes + + sha256hash : str + The SHA-256 hash of the media record + + field : str + The trace / observation field the media record is associated with. This can be one of `input`, `output`, `metadata` + + observation_id : typing.Optional[str] + The observation ID associated with the media record. If the media record is associated directly with a trace, this will be null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetMediaUploadUrlResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.media.get_upload_url( + trace_id="traceId", + content_type="image/png", + content_length=1, + sha256hash="sha256Hash", + field="field", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_upload_url( + trace_id=trace_id, + content_type=content_type, + content_length=content_length, + sha256hash=sha256hash, + field=field, + observation_id=observation_id, + request_options=request_options, + ) + return _response.data diff --git a/langfuse/api/media/raw_client.py b/langfuse/api/media/raw_client.py new file mode 100644 index 000000000..4cc619770 --- /dev/null +++ b/langfuse/api/media/raw_client.py @@ -0,0 +1,739 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.get_media_response import GetMediaResponse +from .types.get_media_upload_url_response import GetMediaUploadUrlResponse +from .types.media_content_type import MediaContentType + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawMediaClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get( + self, media_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[GetMediaResponse]: + """ + Get a media record + + Parameters + ---------- + media_id : str + The unique langfuse identifier of a media record + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[GetMediaResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/media/{jsonable_encoder(media_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GetMediaResponse, + parse_obj_as( + type_=GetMediaResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def patch( + self, + media_id: str, + *, + uploaded_at: dt.datetime, + upload_http_status: int, + upload_http_error: typing.Optional[str] = OMIT, + upload_time_ms: typing.Optional[int] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[None]: + """ + Patch a media record + + Parameters + ---------- + media_id : str + The unique langfuse identifier of a media record + + uploaded_at : dt.datetime + The date and time when the media record was uploaded + + upload_http_status : int + The HTTP status code of the upload + + upload_http_error : typing.Optional[str] + The HTTP error message of the upload + + upload_time_ms : typing.Optional[int] + The time in milliseconds it took to upload the media record + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[None] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/media/{jsonable_encoder(media_id)}", + method="PATCH", + json={ + "uploadedAt": uploaded_at, + "uploadHttpStatus": upload_http_status, + "uploadHttpError": upload_http_error, + "uploadTimeMs": upload_time_ms, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return HttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_upload_url( + self, + *, + trace_id: str, + content_type: MediaContentType, + content_length: int, + sha256hash: str, + field: str, + observation_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[GetMediaUploadUrlResponse]: + """ + Get a presigned upload URL for a media record + + Parameters + ---------- + trace_id : str + The trace ID associated with the media record + + content_type : MediaContentType + + content_length : int + The size of the media record in bytes + + sha256hash : str + The SHA-256 hash of the media record + + field : str + The trace / observation field the media record is associated with. This can be one of `input`, `output`, `metadata` + + observation_id : typing.Optional[str] + The observation ID associated with the media record. If the media record is associated directly with a trace, this will be null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[GetMediaUploadUrlResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/media", + method="POST", + json={ + "traceId": trace_id, + "observationId": observation_id, + "contentType": content_type, + "contentLength": content_length, + "sha256Hash": sha256hash, + "field": field, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GetMediaUploadUrlResponse, + parse_obj_as( + type_=GetMediaUploadUrlResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawMediaClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get( + self, media_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[GetMediaResponse]: + """ + Get a media record + + Parameters + ---------- + media_id : str + The unique langfuse identifier of a media record + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[GetMediaResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/media/{jsonable_encoder(media_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GetMediaResponse, + parse_obj_as( + type_=GetMediaResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def patch( + self, + media_id: str, + *, + uploaded_at: dt.datetime, + upload_http_status: int, + upload_http_error: typing.Optional[str] = OMIT, + upload_time_ms: typing.Optional[int] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[None]: + """ + Patch a media record + + Parameters + ---------- + media_id : str + The unique langfuse identifier of a media record + + uploaded_at : dt.datetime + The date and time when the media record was uploaded + + upload_http_status : int + The HTTP status code of the upload + + upload_http_error : typing.Optional[str] + The HTTP error message of the upload + + upload_time_ms : typing.Optional[int] + The time in milliseconds it took to upload the media record + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[None] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/media/{jsonable_encoder(media_id)}", + method="PATCH", + json={ + "uploadedAt": uploaded_at, + "uploadHttpStatus": upload_http_status, + "uploadHttpError": upload_http_error, + "uploadTimeMs": upload_time_ms, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_upload_url( + self, + *, + trace_id: str, + content_type: MediaContentType, + content_length: int, + sha256hash: str, + field: str, + observation_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[GetMediaUploadUrlResponse]: + """ + Get a presigned upload URL for a media record + + Parameters + ---------- + trace_id : str + The trace ID associated with the media record + + content_type : MediaContentType + + content_length : int + The size of the media record in bytes + + sha256hash : str + The SHA-256 hash of the media record + + field : str + The trace / observation field the media record is associated with. This can be one of `input`, `output`, `metadata` + + observation_id : typing.Optional[str] + The observation ID associated with the media record. If the media record is associated directly with a trace, this will be null. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[GetMediaUploadUrlResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/media", + method="POST", + json={ + "traceId": trace_id, + "observationId": observation_id, + "contentType": content_type, + "contentLength": content_length, + "sha256Hash": sha256hash, + "field": field, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + GetMediaUploadUrlResponse, + parse_obj_as( + type_=GetMediaUploadUrlResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/media/types/__init__.py b/langfuse/api/media/types/__init__.py new file mode 100644 index 000000000..0fb9a44ed --- /dev/null +++ b/langfuse/api/media/types/__init__.py @@ -0,0 +1,56 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .get_media_response import GetMediaResponse + from .get_media_upload_url_request import GetMediaUploadUrlRequest + from .get_media_upload_url_response import GetMediaUploadUrlResponse + from .media_content_type import MediaContentType + from .patch_media_body import PatchMediaBody +_dynamic_imports: typing.Dict[str, str] = { + "GetMediaResponse": ".get_media_response", + "GetMediaUploadUrlRequest": ".get_media_upload_url_request", + "GetMediaUploadUrlResponse": ".get_media_upload_url_response", + "MediaContentType": ".media_content_type", + "PatchMediaBody": ".patch_media_body", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "GetMediaResponse", + "GetMediaUploadUrlRequest", + "GetMediaUploadUrlResponse", + "MediaContentType", + "PatchMediaBody", +] diff --git a/langfuse/api/media/types/get_media_response.py b/langfuse/api/media/types/get_media_response.py new file mode 100644 index 000000000..05b2aff9b --- /dev/null +++ b/langfuse/api/media/types/get_media_response.py @@ -0,0 +1,62 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class GetMediaResponse(UniversalBaseModel): + media_id: typing_extensions.Annotated[str, FieldMetadata(alias="mediaId")] = ( + pydantic.Field() + ) + """ + The unique langfuse identifier of a media record + """ + + content_type: typing_extensions.Annotated[ + str, FieldMetadata(alias="contentType") + ] = pydantic.Field() + """ + The MIME type of the media record + """ + + content_length: typing_extensions.Annotated[ + int, FieldMetadata(alias="contentLength") + ] = pydantic.Field() + """ + The size of the media record in bytes + """ + + uploaded_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="uploadedAt") + ] = pydantic.Field() + """ + The date and time when the media record was uploaded + """ + + url: str = pydantic.Field() + """ + The download URL of the media record + """ + + url_expiry: typing_extensions.Annotated[str, FieldMetadata(alias="urlExpiry")] = ( + pydantic.Field() + ) + """ + The expiry date and time of the media record download URL + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/media/types/get_media_upload_url_request.py b/langfuse/api/media/types/get_media_upload_url_request.py new file mode 100644 index 000000000..6cf733534 --- /dev/null +++ b/langfuse/api/media/types/get_media_upload_url_request.py @@ -0,0 +1,58 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .media_content_type import MediaContentType + + +class GetMediaUploadUrlRequest(UniversalBaseModel): + trace_id: typing_extensions.Annotated[str, FieldMetadata(alias="traceId")] = ( + pydantic.Field() + ) + """ + The trace ID associated with the media record + """ + + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = pydantic.Field(default=None) + """ + The observation ID associated with the media record. If the media record is associated directly with a trace, this will be null. + """ + + content_type: typing_extensions.Annotated[ + MediaContentType, FieldMetadata(alias="contentType") + ] + content_length: typing_extensions.Annotated[ + int, FieldMetadata(alias="contentLength") + ] = pydantic.Field() + """ + The size of the media record in bytes + """ + + sha256hash: typing_extensions.Annotated[str, FieldMetadata(alias="sha256Hash")] = ( + pydantic.Field() + ) + """ + The SHA-256 hash of the media record + """ + + field: str = pydantic.Field() + """ + The trace / observation field the media record is associated with. This can be one of `input`, `output`, `metadata` + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/media/types/get_media_upload_url_response.py b/langfuse/api/media/types/get_media_upload_url_response.py new file mode 100644 index 000000000..5cf03abaa --- /dev/null +++ b/langfuse/api/media/types/get_media_upload_url_response.py @@ -0,0 +1,35 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class GetMediaUploadUrlResponse(UniversalBaseModel): + upload_url: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uploadUrl") + ] = pydantic.Field(default=None) + """ + The presigned upload URL. If the asset is already uploaded, this will be null + """ + + media_id: typing_extensions.Annotated[str, FieldMetadata(alias="mediaId")] = ( + pydantic.Field() + ) + """ + The unique langfuse identifier of a media record + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/media/types/media_content_type.py b/langfuse/api/media/types/media_content_type.py new file mode 100644 index 000000000..0995269ab --- /dev/null +++ b/langfuse/api/media/types/media_content_type.py @@ -0,0 +1,61 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +MediaContentType = typing.Union[ + typing.Literal[ + "image/png", + "image/jpeg", + "image/jpg", + "image/webp", + "image/gif", + "image/svg+xml", + "image/tiff", + "image/bmp", + "image/avif", + "image/heic", + "audio/mpeg", + "audio/mp3", + "audio/wav", + "audio/ogg", + "audio/oga", + "audio/aac", + "audio/mp4", + "audio/flac", + "audio/opus", + "audio/webm", + "video/mp4", + "video/webm", + "video/ogg", + "video/mpeg", + "video/quicktime", + "video/x-msvideo", + "video/x-matroska", + "text/plain", + "text/html", + "text/css", + "text/csv", + "text/markdown", + "text/x-python", + "application/javascript", + "text/x-typescript", + "application/x-yaml", + "application/pdf", + "application/msword", + "application/vnd.ms-excel", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "application/zip", + "application/json", + "application/xml", + "application/octet-stream", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + "application/rtf", + "application/x-ndjson", + "application/vnd.apache.parquet", + "application/gzip", + "application/x-tar", + "application/x-7z-compressed", + ], + typing.Any, +] diff --git a/langfuse/api/media/types/patch_media_body.py b/langfuse/api/media/types/patch_media_body.py new file mode 100644 index 000000000..3f9cc2495 --- /dev/null +++ b/langfuse/api/media/types/patch_media_body.py @@ -0,0 +1,50 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class PatchMediaBody(UniversalBaseModel): + uploaded_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="uploadedAt") + ] = pydantic.Field() + """ + The date and time when the media record was uploaded + """ + + upload_http_status: typing_extensions.Annotated[ + int, FieldMetadata(alias="uploadHttpStatus") + ] = pydantic.Field() + """ + The HTTP status code of the upload + """ + + upload_http_error: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="uploadHttpError") + ] = pydantic.Field(default=None) + """ + The HTTP error message of the upload + """ + + upload_time_ms: typing_extensions.Annotated[ + typing.Optional[int], FieldMetadata(alias="uploadTimeMs") + ] = pydantic.Field(default=None) + """ + The time in milliseconds it took to upload the media record + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/metrics/__init__.py b/langfuse/api/metrics/__init__.py new file mode 100644 index 000000000..fb47bc976 --- /dev/null +++ b/langfuse/api/metrics/__init__.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import MetricsResponse +_dynamic_imports: typing.Dict[str, str] = {"MetricsResponse": ".types"} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["MetricsResponse"] diff --git a/langfuse/api/resources/metrics/client.py b/langfuse/api/metrics/client.py similarity index 64% rename from langfuse/api/resources/metrics/client.py rename to langfuse/api/metrics/client.py index 471f5182e..7b2cc0136 100644 --- a/langfuse/api/resources/metrics/client.py +++ b/langfuse/api/metrics/client.py @@ -1,23 +1,27 @@ # This file was auto-generated by Fern from our API Definition. import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawMetricsClient, RawMetricsClient from .types.metrics_response import MetricsResponse class MetricsClient: def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper + self._raw_client = RawMetricsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawMetricsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawMetricsClient + """ + return self._raw_client def metrics( self, *, query: str, request_options: typing.Optional[RequestOptions] = None @@ -81,9 +85,9 @@ def metrics( Examples -------- - from langfuse.client import FernLangfuse + from langfuse import LangfuseAPI - client = FernLangfuse( + client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -95,42 +99,26 @@ def metrics( query="query", ) """ - _response = self._client_wrapper.httpx_client.request( - "api/public/metrics", - method="GET", - params={"query": query}, - request_options=request_options, + _response = self._raw_client.metrics( + query=query, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(MetricsResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data class AsyncMetricsClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper + self._raw_client = AsyncRawMetricsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawMetricsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawMetricsClient + """ + return self._raw_client async def metrics( self, *, query: str, request_options: typing.Optional[RequestOptions] = None @@ -196,9 +184,9 @@ async def metrics( -------- import asyncio - from langfuse.client import AsyncFernLangfuse + from langfuse import AsyncLangfuseAPI - client = AsyncFernLangfuse( + client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -216,34 +204,7 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/metrics", - method="GET", - params={"query": query}, - request_options=request_options, + _response = await self._raw_client.metrics( + query=query, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(MetricsResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data diff --git a/langfuse/api/metrics/raw_client.py b/langfuse/api/metrics/raw_client.py new file mode 100644 index 000000000..1ce3c1702 --- /dev/null +++ b/langfuse/api/metrics/raw_client.py @@ -0,0 +1,318 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.metrics_response import MetricsResponse + + +class RawMetricsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def metrics( + self, *, query: str, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[MetricsResponse]: + """ + Get metrics from the Langfuse project using a query object. + + For more details, see the [Metrics API documentation](https://langfuse.com/docs/metrics/features/metrics-api). + + Parameters + ---------- + query : str + JSON string containing the query parameters with the following structure: + ```json + { + "view": string, // Required. One of "traces", "observations", "scores-numeric", "scores-categorical" + "dimensions": [ // Optional. Default: [] + { + "field": string // Field to group by, e.g. "name", "userId", "sessionId" + } + ], + "metrics": [ // Required. At least one metric must be provided + { + "measure": string, // What to measure, e.g. "count", "latency", "value" + "aggregation": string // How to aggregate, e.g. "count", "sum", "avg", "p95", "histogram" + } + ], + "filters": [ // Optional. Default: [] + { + "column": string, // Column to filter on + "operator": string, // Operator, e.g. "=", ">", "<", "contains" + "value": any, // Value to compare against + "type": string, // Data type, e.g. "string", "number", "stringObject" + "key": string // Required only when filtering on metadata + } + ], + "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time + "granularity": string // One of "minute", "hour", "day", "week", "month", "auto" + }, + "fromTimestamp": string, // Required. ISO datetime string for start of time range + "toTimestamp": string, // Required. ISO datetime string for end of time range + "orderBy": [ // Optional. Default: null + { + "field": string, // Field to order by + "direction": string // "asc" or "desc" + } + ], + "config": { // Optional. Query-specific configuration + "bins": number, // Optional. Number of bins for histogram (1-100), default: 10 + "row_limit": number // Optional. Row limit for results (1-1000) + } + } + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[MetricsResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/metrics", + method="GET", + params={ + "query": query, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MetricsResponse, + parse_obj_as( + type_=MetricsResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawMetricsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def metrics( + self, *, query: str, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[MetricsResponse]: + """ + Get metrics from the Langfuse project using a query object. + + For more details, see the [Metrics API documentation](https://langfuse.com/docs/metrics/features/metrics-api). + + Parameters + ---------- + query : str + JSON string containing the query parameters with the following structure: + ```json + { + "view": string, // Required. One of "traces", "observations", "scores-numeric", "scores-categorical" + "dimensions": [ // Optional. Default: [] + { + "field": string // Field to group by, e.g. "name", "userId", "sessionId" + } + ], + "metrics": [ // Required. At least one metric must be provided + { + "measure": string, // What to measure, e.g. "count", "latency", "value" + "aggregation": string // How to aggregate, e.g. "count", "sum", "avg", "p95", "histogram" + } + ], + "filters": [ // Optional. Default: [] + { + "column": string, // Column to filter on + "operator": string, // Operator, e.g. "=", ">", "<", "contains" + "value": any, // Value to compare against + "type": string, // Data type, e.g. "string", "number", "stringObject" + "key": string // Required only when filtering on metadata + } + ], + "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time + "granularity": string // One of "minute", "hour", "day", "week", "month", "auto" + }, + "fromTimestamp": string, // Required. ISO datetime string for start of time range + "toTimestamp": string, // Required. ISO datetime string for end of time range + "orderBy": [ // Optional. Default: null + { + "field": string, // Field to order by + "direction": string // "asc" or "desc" + } + ], + "config": { // Optional. Query-specific configuration + "bins": number, // Optional. Number of bins for histogram (1-100), default: 10 + "row_limit": number // Optional. Row limit for results (1-1000) + } + } + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[MetricsResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/metrics", + method="GET", + params={ + "query": query, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MetricsResponse, + parse_obj_as( + type_=MetricsResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/metrics/types/__init__.py b/langfuse/api/metrics/types/__init__.py new file mode 100644 index 000000000..308847504 --- /dev/null +++ b/langfuse/api/metrics/types/__init__.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .metrics_response import MetricsResponse +_dynamic_imports: typing.Dict[str, str] = {"MetricsResponse": ".metrics_response"} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["MetricsResponse"] diff --git a/langfuse/api/metrics/types/metrics_response.py b/langfuse/api/metrics/types/metrics_response.py new file mode 100644 index 000000000..ece54976c --- /dev/null +++ b/langfuse/api/metrics/types/metrics_response.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class MetricsResponse(UniversalBaseModel): + data: typing.List[typing.Dict[str, typing.Any]] = pydantic.Field() + """ + The metrics data. Each item in the list contains the metric values and dimensions requested in the query. + Format varies based on the query parameters. + Histograms will return an array with [lower, upper, height] tuples. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/models/__init__.py b/langfuse/api/models/__init__.py new file mode 100644 index 000000000..7ebdb7762 --- /dev/null +++ b/langfuse/api/models/__init__.py @@ -0,0 +1,43 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import CreateModelRequest, PaginatedModels +_dynamic_imports: typing.Dict[str, str] = { + "CreateModelRequest": ".types", + "PaginatedModels": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["CreateModelRequest", "PaginatedModels"] diff --git a/langfuse/api/models/client.py b/langfuse/api/models/client.py new file mode 100644 index 000000000..9f817b8f6 --- /dev/null +++ b/langfuse/api/models/client.py @@ -0,0 +1,523 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ..commons.types.model import Model +from ..commons.types.model_usage_unit import ModelUsageUnit +from ..commons.types.pricing_tier_input import PricingTierInput +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawModelsClient, RawModelsClient +from .types.paginated_models import PaginatedModels + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class ModelsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawModelsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawModelsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawModelsClient + """ + return self._raw_client + + def create( + self, + *, + model_name: str, + match_pattern: str, + start_date: typing.Optional[dt.datetime] = OMIT, + unit: typing.Optional[ModelUsageUnit] = OMIT, + input_price: typing.Optional[float] = OMIT, + output_price: typing.Optional[float] = OMIT, + total_price: typing.Optional[float] = OMIT, + pricing_tiers: typing.Optional[typing.Sequence[PricingTierInput]] = OMIT, + tokenizer_id: typing.Optional[str] = OMIT, + tokenizer_config: typing.Optional[typing.Any] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Model: + """ + Create a model + + Parameters + ---------- + model_name : str + Name of the model definition. If multiple with the same name exist, they are applied in the following order: (1) custom over built-in, (2) newest according to startTime where model.startTime PaginatedModels: + """ + Get all models + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedModels + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.models.list() + """ + _response = self._raw_client.list( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + def get( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> Model: + """ + Get a model + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Model + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.models.get( + id="id", + ) + """ + _response = self._raw_client.get(id, request_options=request_options) + return _response.data + + def delete( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Delete a model. Cannot delete models managed by Langfuse. You can create your own definition with the same modelName to override the definition though. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.models.delete( + id="id", + ) + """ + _response = self._raw_client.delete(id, request_options=request_options) + return _response.data + + +class AsyncModelsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawModelsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawModelsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawModelsClient + """ + return self._raw_client + + async def create( + self, + *, + model_name: str, + match_pattern: str, + start_date: typing.Optional[dt.datetime] = OMIT, + unit: typing.Optional[ModelUsageUnit] = OMIT, + input_price: typing.Optional[float] = OMIT, + output_price: typing.Optional[float] = OMIT, + total_price: typing.Optional[float] = OMIT, + pricing_tiers: typing.Optional[typing.Sequence[PricingTierInput]] = OMIT, + tokenizer_id: typing.Optional[str] = OMIT, + tokenizer_config: typing.Optional[typing.Any] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Model: + """ + Create a model + + Parameters + ---------- + model_name : str + Name of the model definition. If multiple with the same name exist, they are applied in the following order: (1) custom over built-in, (2) newest according to startTime where model.startTime None: + await client.models.create( + model_name="modelName", + match_pattern="matchPattern", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create( + model_name=model_name, + match_pattern=match_pattern, + start_date=start_date, + unit=unit, + input_price=input_price, + output_price=output_price, + total_price=total_price, + pricing_tiers=pricing_tiers, + tokenizer_id=tokenizer_id, + tokenizer_config=tokenizer_config, + request_options=request_options, + ) + return _response.data + + async def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedModels: + """ + Get all models + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedModels + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.models.list() + + + asyncio.run(main()) + """ + _response = await self._raw_client.list( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + async def get( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> Model: + """ + Get a model + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Model + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.models.get( + id="id", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get(id, request_options=request_options) + return _response.data + + async def delete( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Delete a model. Cannot delete models managed by Langfuse. You can create your own definition with the same modelName to override the definition though. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.models.delete( + id="id", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete(id, request_options=request_options) + return _response.data diff --git a/langfuse/api/models/raw_client.py b/langfuse/api/models/raw_client.py new file mode 100644 index 000000000..0fdc72319 --- /dev/null +++ b/langfuse/api/models/raw_client.py @@ -0,0 +1,993 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..commons.types.model import Model +from ..commons.types.model_usage_unit import ModelUsageUnit +from ..commons.types.pricing_tier_input import PricingTierInput +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from ..core.serialization import convert_and_respect_annotation_metadata +from .types.paginated_models import PaginatedModels + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawModelsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def create( + self, + *, + model_name: str, + match_pattern: str, + start_date: typing.Optional[dt.datetime] = OMIT, + unit: typing.Optional[ModelUsageUnit] = OMIT, + input_price: typing.Optional[float] = OMIT, + output_price: typing.Optional[float] = OMIT, + total_price: typing.Optional[float] = OMIT, + pricing_tiers: typing.Optional[typing.Sequence[PricingTierInput]] = OMIT, + tokenizer_id: typing.Optional[str] = OMIT, + tokenizer_config: typing.Optional[typing.Any] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Model]: + """ + Create a model + + Parameters + ---------- + model_name : str + Name of the model definition. If multiple with the same name exist, they are applied in the following order: (1) custom over built-in, (2) newest according to startTime where model.startTime HttpResponse[PaginatedModels]: + """ + Get all models + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[PaginatedModels] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/models", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedModels, + parse_obj_as( + type_=PaginatedModels, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[Model]: + """ + Get a model + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Model] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/models/{jsonable_encoder(id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Model, + parse_obj_as( + type_=Model, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[None]: + """ + Delete a model. Cannot delete models managed by Langfuse. You can create your own definition with the same modelName to override the definition though. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[None] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/models/{jsonable_encoder(id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return HttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawModelsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def create( + self, + *, + model_name: str, + match_pattern: str, + start_date: typing.Optional[dt.datetime] = OMIT, + unit: typing.Optional[ModelUsageUnit] = OMIT, + input_price: typing.Optional[float] = OMIT, + output_price: typing.Optional[float] = OMIT, + total_price: typing.Optional[float] = OMIT, + pricing_tiers: typing.Optional[typing.Sequence[PricingTierInput]] = OMIT, + tokenizer_id: typing.Optional[str] = OMIT, + tokenizer_config: typing.Optional[typing.Any] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Model]: + """ + Create a model + + Parameters + ---------- + model_name : str + Name of the model definition. If multiple with the same name exist, they are applied in the following order: (1) custom over built-in, (2) newest according to startTime where model.startTime AsyncHttpResponse[PaginatedModels]: + """ + Get all models + + Parameters + ---------- + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[PaginatedModels] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/models", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedModels, + parse_obj_as( + type_=PaginatedModels, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[Model]: + """ + Get a model + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Model] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/models/{jsonable_encoder(id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Model, + parse_obj_as( + type_=Model, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete( + self, id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[None]: + """ + Delete a model. Cannot delete models managed by Langfuse. You can create your own definition with the same modelName to override the definition though. + + Parameters + ---------- + id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[None] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/models/{jsonable_encoder(id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/models/types/__init__.py b/langfuse/api/models/types/__init__.py new file mode 100644 index 000000000..8b4b651c5 --- /dev/null +++ b/langfuse/api/models/types/__init__.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .create_model_request import CreateModelRequest + from .paginated_models import PaginatedModels +_dynamic_imports: typing.Dict[str, str] = { + "CreateModelRequest": ".create_model_request", + "PaginatedModels": ".paginated_models", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["CreateModelRequest", "PaginatedModels"] diff --git a/langfuse/api/resources/models/types/create_model_request.py b/langfuse/api/models/types/create_model_request.py similarity index 53% rename from langfuse/api/resources/models/types/create_model_request.py rename to langfuse/api/models/types/create_model_request.py index 3f9f80119..c03436ec5 100644 --- a/langfuse/api/resources/models/types/create_model_request.py +++ b/langfuse/api/models/types/create_model_request.py @@ -3,59 +3,66 @@ import datetime as dt import typing -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 +import pydantic +import typing_extensions from ...commons.types.model_usage_unit import ModelUsageUnit from ...commons.types.pricing_tier_input import PricingTierInput +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata -class CreateModelRequest(pydantic_v1.BaseModel): - model_name: str = pydantic_v1.Field(alias="modelName") +class CreateModelRequest(UniversalBaseModel): + model_name: typing_extensions.Annotated[str, FieldMetadata(alias="modelName")] = ( + pydantic.Field() + ) """ Name of the model definition. If multiple with the same name exist, they are applied in the following order: (1) custom over built-in, (2) newest according to startTime where model.startTime str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/models/types/paginated_models.py b/langfuse/api/models/types/paginated_models.py new file mode 100644 index 000000000..f0a441246 --- /dev/null +++ b/langfuse/api/models/types/paginated_models.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.model import Model +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse + + +class PaginatedModels(UniversalBaseModel): + data: typing.List[Model] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/observations/__init__.py b/langfuse/api/observations/__init__.py new file mode 100644 index 000000000..22b445984 --- /dev/null +++ b/langfuse/api/observations/__init__.py @@ -0,0 +1,43 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import Observations, ObservationsViews +_dynamic_imports: typing.Dict[str, str] = { + "Observations": ".types", + "ObservationsViews": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["Observations", "ObservationsViews"] diff --git a/langfuse/api/resources/observations/client.py b/langfuse/api/observations/client.py similarity index 67% rename from langfuse/api/resources/observations/client.py rename to langfuse/api/observations/client.py index cac4efe4d..0d292a442 100644 --- a/langfuse/api/resources/observations/client.py +++ b/langfuse/api/observations/client.py @@ -2,27 +2,29 @@ import datetime as dt import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.datetime_utils import serialize_datetime -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError + from ..commons.types.observation_level import ObservationLevel from ..commons.types.observations_view import ObservationsView +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawObservationsClient, RawObservationsClient from .types.observations_views import ObservationsViews class ObservationsClient: def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper + self._raw_client = RawObservationsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawObservationsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawObservationsClient + """ + return self._raw_client def get( self, @@ -47,9 +49,9 @@ def get( Examples -------- - from langfuse.client import FernLangfuse + from langfuse import LangfuseAPI - client = FernLangfuse( + client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -61,36 +63,10 @@ def get( observation_id="observationId", ) """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/observations/{jsonable_encoder(observation_id)}", - method="GET", - request_options=request_options, + _response = self._raw_client.get( + observation_id, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ObservationsView, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data def get_many( self, @@ -250,9 +226,9 @@ def get_many( Examples -------- - from langfuse.client import FernLangfuse + from langfuse import LangfuseAPI - client = FernLangfuse( + client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -262,60 +238,39 @@ def get_many( ) client.observations.get_many() """ - _response = self._client_wrapper.httpx_client.request( - "api/public/observations", - method="GET", - params={ - "page": page, - "limit": limit, - "name": name, - "userId": user_id, - "type": type, - "traceId": trace_id, - "level": level, - "parentObservationId": parent_observation_id, - "environment": environment, - "fromStartTime": serialize_datetime(from_start_time) - if from_start_time is not None - else None, - "toStartTime": serialize_datetime(to_start_time) - if to_start_time is not None - else None, - "version": version, - "filter": filter, - }, + _response = self._raw_client.get_many( + page=page, + limit=limit, + name=name, + user_id=user_id, + type=type, + trace_id=trace_id, + level=level, + parent_observation_id=parent_observation_id, + environment=environment, + from_start_time=from_start_time, + to_start_time=to_start_time, + version=version, + filter=filter, request_options=request_options, ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ObservationsViews, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data class AsyncObservationsClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper + self._raw_client = AsyncRawObservationsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawObservationsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawObservationsClient + """ + return self._raw_client async def get( self, @@ -342,9 +297,9 @@ async def get( -------- import asyncio - from langfuse.client import AsyncFernLangfuse + from langfuse import AsyncLangfuseAPI - client = AsyncFernLangfuse( + client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -362,36 +317,10 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/observations/{jsonable_encoder(observation_id)}", - method="GET", - request_options=request_options, + _response = await self._raw_client.get( + observation_id, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ObservationsView, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data async def get_many( self, @@ -553,9 +482,9 @@ async def get_many( -------- import asyncio - from langfuse.client import AsyncFernLangfuse + from langfuse import AsyncLangfuseAPI - client = AsyncFernLangfuse( + client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -571,52 +500,20 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/observations", - method="GET", - params={ - "page": page, - "limit": limit, - "name": name, - "userId": user_id, - "type": type, - "traceId": trace_id, - "level": level, - "parentObservationId": parent_observation_id, - "environment": environment, - "fromStartTime": serialize_datetime(from_start_time) - if from_start_time is not None - else None, - "toStartTime": serialize_datetime(to_start_time) - if to_start_time is not None - else None, - "version": version, - "filter": filter, - }, + _response = await self._raw_client.get_many( + page=page, + limit=limit, + name=name, + user_id=user_id, + type=type, + trace_id=trace_id, + level=level, + parent_observation_id=parent_observation_id, + environment=environment, + from_start_time=from_start_time, + to_start_time=to_start_time, + version=version, + filter=filter, request_options=request_options, ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ObservationsViews, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data diff --git a/langfuse/api/observations/raw_client.py b/langfuse/api/observations/raw_client.py new file mode 100644 index 000000000..f87c0f044 --- /dev/null +++ b/langfuse/api/observations/raw_client.py @@ -0,0 +1,755 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..commons.types.observation_level import ObservationLevel +from ..commons.types.observations_view import ObservationsView +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.datetime_utils import serialize_datetime +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.observations_views import ObservationsViews + + +class RawObservationsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get( + self, + observation_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ObservationsView]: + """ + Get a observation + + Parameters + ---------- + observation_id : str + The unique langfuse identifier of an observation, can be an event, span or generation + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ObservationsView] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/observations/{jsonable_encoder(observation_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ObservationsView, + parse_obj_as( + type_=ObservationsView, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_many( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + name: typing.Optional[str] = None, + user_id: typing.Optional[str] = None, + type: typing.Optional[str] = None, + trace_id: typing.Optional[str] = None, + level: typing.Optional[ObservationLevel] = None, + parent_observation_id: typing.Optional[str] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + from_start_time: typing.Optional[dt.datetime] = None, + to_start_time: typing.Optional[dt.datetime] = None, + version: typing.Optional[str] = None, + filter: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ObservationsViews]: + """ + Get a list of observations + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. + + name : typing.Optional[str] + + user_id : typing.Optional[str] + + type : typing.Optional[str] + + trace_id : typing.Optional[str] + + level : typing.Optional[ObservationLevel] + Optional filter for observations with a specific level (e.g. "DEBUG", "DEFAULT", "WARNING", "ERROR"). + + parent_observation_id : typing.Optional[str] + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for observations where the environment is one of the provided values. + + from_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time on or after this datetime (ISO 8601). + + to_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time before this datetime (ISO 8601). + + version : typing.Optional[str] + Optional filter to only include observations with a certain version. + + filter : typing.Optional[str] + JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, type, level, environment, fromStartTime, ...). + + ## Filter Structure + Each filter condition has the following structure: + ```json + [ + { + "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "column": string, // Required. Column to filter on (see available columns below) + "operator": string, // Required. Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - categoryOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject: "=", "contains", "does not contain", "starts with", "ends with" + // - numberObject: "=", ">", "<", ">=", "<=" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Required (except for null type). Value to compare against. Type depends on filter type + "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata + } + ] + ``` + + ## Available Columns + + ### Core Observation Fields + - `id` (string) - Observation ID + - `type` (string) - Observation type (SPAN, GENERATION, EVENT) + - `name` (string) - Observation name + - `traceId` (string) - Associated trace ID + - `startTime` (datetime) - Observation start time + - `endTime` (datetime) - Observation end time + - `environment` (string) - Environment tag + - `level` (string) - Log level (DEBUG, DEFAULT, WARNING, ERROR) + - `statusMessage` (string) - Status message + - `version` (string) - Version tag + + ### Performance Metrics + - `latency` (number) - Latency in seconds (calculated: end_time - start_time) + - `timeToFirstToken` (number) - Time to first token in seconds + - `tokensPerSecond` (number) - Output tokens per second + + ### Token Usage + - `inputTokens` (number) - Number of input tokens + - `outputTokens` (number) - Number of output tokens + - `totalTokens` (number) - Total tokens (alias: `tokens`) + + ### Cost Metrics + - `inputCost` (number) - Input cost in USD + - `outputCost` (number) - Output cost in USD + - `totalCost` (number) - Total cost in USD + + ### Model Information + - `model` (string) - Provided model name + - `promptName` (string) - Associated prompt name + - `promptVersion` (number) - Associated prompt version + + ### Structured Data + - `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys. + + ### Associated Trace Fields (requires join with traces table) + - `userId` (string) - User ID from associated trace + - `traceName` (string) - Name from associated trace + - `traceEnvironment` (string) - Environment from associated trace + - `traceTags` (arrayOptions) - Tags from associated trace + + ## Filter Examples + ```json + [ + { + "type": "string", + "column": "type", + "operator": "=", + "value": "GENERATION" + }, + { + "type": "number", + "column": "latency", + "operator": ">=", + "value": 2.5 + }, + { + "type": "stringObject", + "column": "metadata", + "key": "environment", + "operator": "=", + "value": "production" + } + ] + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ObservationsViews] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/observations", + method="GET", + params={ + "page": page, + "limit": limit, + "name": name, + "userId": user_id, + "type": type, + "traceId": trace_id, + "level": level, + "parentObservationId": parent_observation_id, + "environment": environment, + "fromStartTime": serialize_datetime(from_start_time) + if from_start_time is not None + else None, + "toStartTime": serialize_datetime(to_start_time) + if to_start_time is not None + else None, + "version": version, + "filter": filter, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ObservationsViews, + parse_obj_as( + type_=ObservationsViews, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawObservationsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get( + self, + observation_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ObservationsView]: + """ + Get a observation + + Parameters + ---------- + observation_id : str + The unique langfuse identifier of an observation, can be an event, span or generation + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ObservationsView] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/observations/{jsonable_encoder(observation_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ObservationsView, + parse_obj_as( + type_=ObservationsView, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_many( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + name: typing.Optional[str] = None, + user_id: typing.Optional[str] = None, + type: typing.Optional[str] = None, + trace_id: typing.Optional[str] = None, + level: typing.Optional[ObservationLevel] = None, + parent_observation_id: typing.Optional[str] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + from_start_time: typing.Optional[dt.datetime] = None, + to_start_time: typing.Optional[dt.datetime] = None, + version: typing.Optional[str] = None, + filter: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ObservationsViews]: + """ + Get a list of observations + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. + + name : typing.Optional[str] + + user_id : typing.Optional[str] + + type : typing.Optional[str] + + trace_id : typing.Optional[str] + + level : typing.Optional[ObservationLevel] + Optional filter for observations with a specific level (e.g. "DEBUG", "DEFAULT", "WARNING", "ERROR"). + + parent_observation_id : typing.Optional[str] + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for observations where the environment is one of the provided values. + + from_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time on or after this datetime (ISO 8601). + + to_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time before this datetime (ISO 8601). + + version : typing.Optional[str] + Optional filter to only include observations with a certain version. + + filter : typing.Optional[str] + JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, type, level, environment, fromStartTime, ...). + + ## Filter Structure + Each filter condition has the following structure: + ```json + [ + { + "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "column": string, // Required. Column to filter on (see available columns below) + "operator": string, // Required. Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - categoryOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject: "=", "contains", "does not contain", "starts with", "ends with" + // - numberObject: "=", ">", "<", ">=", "<=" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Required (except for null type). Value to compare against. Type depends on filter type + "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata + } + ] + ``` + + ## Available Columns + + ### Core Observation Fields + - `id` (string) - Observation ID + - `type` (string) - Observation type (SPAN, GENERATION, EVENT) + - `name` (string) - Observation name + - `traceId` (string) - Associated trace ID + - `startTime` (datetime) - Observation start time + - `endTime` (datetime) - Observation end time + - `environment` (string) - Environment tag + - `level` (string) - Log level (DEBUG, DEFAULT, WARNING, ERROR) + - `statusMessage` (string) - Status message + - `version` (string) - Version tag + + ### Performance Metrics + - `latency` (number) - Latency in seconds (calculated: end_time - start_time) + - `timeToFirstToken` (number) - Time to first token in seconds + - `tokensPerSecond` (number) - Output tokens per second + + ### Token Usage + - `inputTokens` (number) - Number of input tokens + - `outputTokens` (number) - Number of output tokens + - `totalTokens` (number) - Total tokens (alias: `tokens`) + + ### Cost Metrics + - `inputCost` (number) - Input cost in USD + - `outputCost` (number) - Output cost in USD + - `totalCost` (number) - Total cost in USD + + ### Model Information + - `model` (string) - Provided model name + - `promptName` (string) - Associated prompt name + - `promptVersion` (number) - Associated prompt version + + ### Structured Data + - `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys. + + ### Associated Trace Fields (requires join with traces table) + - `userId` (string) - User ID from associated trace + - `traceName` (string) - Name from associated trace + - `traceEnvironment` (string) - Environment from associated trace + - `traceTags` (arrayOptions) - Tags from associated trace + + ## Filter Examples + ```json + [ + { + "type": "string", + "column": "type", + "operator": "=", + "value": "GENERATION" + }, + { + "type": "number", + "column": "latency", + "operator": ">=", + "value": 2.5 + }, + { + "type": "stringObject", + "column": "metadata", + "key": "environment", + "operator": "=", + "value": "production" + } + ] + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ObservationsViews] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/observations", + method="GET", + params={ + "page": page, + "limit": limit, + "name": name, + "userId": user_id, + "type": type, + "traceId": trace_id, + "level": level, + "parentObservationId": parent_observation_id, + "environment": environment, + "fromStartTime": serialize_datetime(from_start_time) + if from_start_time is not None + else None, + "toStartTime": serialize_datetime(to_start_time) + if to_start_time is not None + else None, + "version": version, + "filter": filter, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ObservationsViews, + parse_obj_as( + type_=ObservationsViews, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/observations/types/__init__.py b/langfuse/api/observations/types/__init__.py new file mode 100644 index 000000000..247b674a1 --- /dev/null +++ b/langfuse/api/observations/types/__init__.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .observations import Observations + from .observations_views import ObservationsViews +_dynamic_imports: typing.Dict[str, str] = { + "Observations": ".observations", + "ObservationsViews": ".observations_views", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["Observations", "ObservationsViews"] diff --git a/langfuse/api/observations/types/observations.py b/langfuse/api/observations/types/observations.py new file mode 100644 index 000000000..190d429fd --- /dev/null +++ b/langfuse/api/observations/types/observations.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.observation import Observation +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse + + +class Observations(UniversalBaseModel): + data: typing.List[Observation] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/observations/types/observations_views.py b/langfuse/api/observations/types/observations_views.py new file mode 100644 index 000000000..e14eaf1a8 --- /dev/null +++ b/langfuse/api/observations/types/observations_views.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.observations_view import ObservationsView +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse + + +class ObservationsViews(UniversalBaseModel): + data: typing.List[ObservationsView] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/opentelemetry/__init__.py b/langfuse/api/opentelemetry/__init__.py new file mode 100644 index 000000000..30caa3796 --- /dev/null +++ b/langfuse/api/opentelemetry/__init__.py @@ -0,0 +1,67 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + OtelAttribute, + OtelAttributeValue, + OtelResource, + OtelResourceSpan, + OtelScope, + OtelScopeSpan, + OtelSpan, + OtelTraceResponse, + ) +_dynamic_imports: typing.Dict[str, str] = { + "OtelAttribute": ".types", + "OtelAttributeValue": ".types", + "OtelResource": ".types", + "OtelResourceSpan": ".types", + "OtelScope": ".types", + "OtelScopeSpan": ".types", + "OtelSpan": ".types", + "OtelTraceResponse": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "OtelAttribute", + "OtelAttributeValue", + "OtelResource", + "OtelResourceSpan", + "OtelScope", + "OtelScopeSpan", + "OtelSpan", + "OtelTraceResponse", +] diff --git a/langfuse/api/resources/opentelemetry/client.py b/langfuse/api/opentelemetry/client.py similarity index 69% rename from langfuse/api/resources/opentelemetry/client.py rename to langfuse/api/opentelemetry/client.py index de17949d4..13177e5e6 100644 --- a/langfuse/api/resources/opentelemetry/client.py +++ b/langfuse/api/opentelemetry/client.py @@ -1,17 +1,10 @@ # This file was auto-generated by Fern from our API Definition. import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawOpentelemetryClient, RawOpentelemetryClient from .types.otel_resource_span import OtelResourceSpan from .types.otel_trace_response import OtelTraceResponse @@ -21,7 +14,18 @@ class OpentelemetryClient: def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper + self._raw_client = RawOpentelemetryClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawOpentelemetryClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawOpentelemetryClient + """ + return self._raw_client def export_traces( self, @@ -61,7 +65,8 @@ def export_traces( Examples -------- - from langfuse import ( + from langfuse import LangfuseAPI + from langfuse.opentelemetry import ( OtelAttribute, OtelAttributeValue, OtelResource, @@ -70,9 +75,8 @@ def export_traces( OtelScopeSpan, OtelSpan, ) - from langfuse.client import FernLangfuse - client = FernLangfuse( + client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -130,43 +134,26 @@ def export_traces( ], ) """ - _response = self._client_wrapper.httpx_client.request( - "api/public/otel/v1/traces", - method="POST", - json={"resourceSpans": resource_spans}, - request_options=request_options, - omit=OMIT, + _response = self._raw_client.export_traces( + resource_spans=resource_spans, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(OtelTraceResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data class AsyncOpentelemetryClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper + self._raw_client = AsyncRawOpentelemetryClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawOpentelemetryClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawOpentelemetryClient + """ + return self._raw_client async def export_traces( self, @@ -208,7 +195,8 @@ async def export_traces( -------- import asyncio - from langfuse import ( + from langfuse import AsyncLangfuseAPI + from langfuse.opentelemetry import ( OtelAttribute, OtelAttributeValue, OtelResource, @@ -217,9 +205,8 @@ async def export_traces( OtelScopeSpan, OtelSpan, ) - from langfuse.client import AsyncFernLangfuse - client = AsyncFernLangfuse( + client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -283,35 +270,7 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/otel/v1/traces", - method="POST", - json={"resourceSpans": resource_spans}, - request_options=request_options, - omit=OMIT, + _response = await self._raw_client.export_traces( + resource_spans=resource_spans, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(OtelTraceResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data diff --git a/langfuse/api/opentelemetry/raw_client.py b/langfuse/api/opentelemetry/raw_client.py new file mode 100644 index 000000000..6b68f909b --- /dev/null +++ b/langfuse/api/opentelemetry/raw_client.py @@ -0,0 +1,291 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from ..core.serialization import convert_and_respect_annotation_metadata +from .types.otel_resource_span import OtelResourceSpan +from .types.otel_trace_response import OtelTraceResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawOpentelemetryClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def export_traces( + self, + *, + resource_spans: typing.Sequence[OtelResourceSpan], + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[OtelTraceResponse]: + """ + **OpenTelemetry Traces Ingestion Endpoint** + + This endpoint implements the OTLP/HTTP specification for trace ingestion, providing native OpenTelemetry integration for Langfuse Observability. + + **Supported Formats:** + - Binary Protobuf: `Content-Type: application/x-protobuf` + - JSON Protobuf: `Content-Type: application/json` + - Supports gzip compression via `Content-Encoding: gzip` header + + **Specification Compliance:** + - Conforms to [OTLP/HTTP Trace Export](https://opentelemetry.io/docs/specs/otlp/#otlphttp) + - Implements `ExportTraceServiceRequest` message format + + **Documentation:** + - Integration guide: https://langfuse.com/integrations/native/opentelemetry + - Data model: https://langfuse.com/docs/observability/data-model + + Parameters + ---------- + resource_spans : typing.Sequence[OtelResourceSpan] + Array of resource spans containing trace data as defined in the OTLP specification + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[OtelTraceResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/otel/v1/traces", + method="POST", + json={ + "resourceSpans": convert_and_respect_annotation_metadata( + object_=resource_spans, + annotation=typing.Sequence[OtelResourceSpan], + direction="write", + ), + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + OtelTraceResponse, + parse_obj_as( + type_=OtelTraceResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawOpentelemetryClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def export_traces( + self, + *, + resource_spans: typing.Sequence[OtelResourceSpan], + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[OtelTraceResponse]: + """ + **OpenTelemetry Traces Ingestion Endpoint** + + This endpoint implements the OTLP/HTTP specification for trace ingestion, providing native OpenTelemetry integration for Langfuse Observability. + + **Supported Formats:** + - Binary Protobuf: `Content-Type: application/x-protobuf` + - JSON Protobuf: `Content-Type: application/json` + - Supports gzip compression via `Content-Encoding: gzip` header + + **Specification Compliance:** + - Conforms to [OTLP/HTTP Trace Export](https://opentelemetry.io/docs/specs/otlp/#otlphttp) + - Implements `ExportTraceServiceRequest` message format + + **Documentation:** + - Integration guide: https://langfuse.com/integrations/native/opentelemetry + - Data model: https://langfuse.com/docs/observability/data-model + + Parameters + ---------- + resource_spans : typing.Sequence[OtelResourceSpan] + Array of resource spans containing trace data as defined in the OTLP specification + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[OtelTraceResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/otel/v1/traces", + method="POST", + json={ + "resourceSpans": convert_and_respect_annotation_metadata( + object_=resource_spans, + annotation=typing.Sequence[OtelResourceSpan], + direction="write", + ), + }, + headers={ + "content-type": "application/json", + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + OtelTraceResponse, + parse_obj_as( + type_=OtelTraceResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/opentelemetry/types/__init__.py b/langfuse/api/opentelemetry/types/__init__.py new file mode 100644 index 000000000..ad2fd4899 --- /dev/null +++ b/langfuse/api/opentelemetry/types/__init__.py @@ -0,0 +1,65 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .otel_attribute import OtelAttribute + from .otel_attribute_value import OtelAttributeValue + from .otel_resource import OtelResource + from .otel_resource_span import OtelResourceSpan + from .otel_scope import OtelScope + from .otel_scope_span import OtelScopeSpan + from .otel_span import OtelSpan + from .otel_trace_response import OtelTraceResponse +_dynamic_imports: typing.Dict[str, str] = { + "OtelAttribute": ".otel_attribute", + "OtelAttributeValue": ".otel_attribute_value", + "OtelResource": ".otel_resource", + "OtelResourceSpan": ".otel_resource_span", + "OtelScope": ".otel_scope", + "OtelScopeSpan": ".otel_scope_span", + "OtelSpan": ".otel_span", + "OtelTraceResponse": ".otel_trace_response", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "OtelAttribute", + "OtelAttributeValue", + "OtelResource", + "OtelResourceSpan", + "OtelScope", + "OtelScopeSpan", + "OtelSpan", + "OtelTraceResponse", +] diff --git a/langfuse/api/opentelemetry/types/otel_attribute.py b/langfuse/api/opentelemetry/types/otel_attribute.py new file mode 100644 index 000000000..61646c471 --- /dev/null +++ b/langfuse/api/opentelemetry/types/otel_attribute.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .otel_attribute_value import OtelAttributeValue + + +class OtelAttribute(UniversalBaseModel): + """ + Key-value attribute pair for resources, scopes, or spans + """ + + key: typing.Optional[str] = pydantic.Field(default=None) + """ + Attribute key (e.g., "service.name", "langfuse.observation.type") + """ + + value: typing.Optional[OtelAttributeValue] = pydantic.Field(default=None) + """ + Attribute value + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/opentelemetry/types/otel_attribute_value.py b/langfuse/api/opentelemetry/types/otel_attribute_value.py new file mode 100644 index 000000000..059ca7661 --- /dev/null +++ b/langfuse/api/opentelemetry/types/otel_attribute_value.py @@ -0,0 +1,53 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class OtelAttributeValue(UniversalBaseModel): + """ + Attribute value wrapper supporting different value types + """ + + string_value: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="stringValue") + ] = pydantic.Field(default=None) + """ + String value + """ + + int_value: typing_extensions.Annotated[ + typing.Optional[int], FieldMetadata(alias="intValue") + ] = pydantic.Field(default=None) + """ + Integer value + """ + + double_value: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="doubleValue") + ] = pydantic.Field(default=None) + """ + Double value + """ + + bool_value: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="boolValue") + ] = pydantic.Field(default=None) + """ + Boolean value + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/opentelemetry/types/otel_resource.py b/langfuse/api/opentelemetry/types/otel_resource.py new file mode 100644 index 000000000..1f86e6d3e --- /dev/null +++ b/langfuse/api/opentelemetry/types/otel_resource.py @@ -0,0 +1,31 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .otel_attribute import OtelAttribute + + +class OtelResource(UniversalBaseModel): + """ + Resource attributes identifying the source of telemetry + """ + + attributes: typing.Optional[typing.List[OtelAttribute]] = pydantic.Field( + default=None + ) + """ + Resource attributes like service.name, service.version, etc. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/opentelemetry/types/otel_resource_span.py b/langfuse/api/opentelemetry/types/otel_resource_span.py new file mode 100644 index 000000000..feea26eb7 --- /dev/null +++ b/langfuse/api/opentelemetry/types/otel_resource_span.py @@ -0,0 +1,39 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .otel_resource import OtelResource +from .otel_scope_span import OtelScopeSpan + + +class OtelResourceSpan(UniversalBaseModel): + """ + Represents a collection of spans from a single resource as per OTLP specification + """ + + resource: typing.Optional[OtelResource] = pydantic.Field(default=None) + """ + Resource information + """ + + scope_spans: typing_extensions.Annotated[ + typing.Optional[typing.List[OtelScopeSpan]], FieldMetadata(alias="scopeSpans") + ] = pydantic.Field(default=None) + """ + Array of scope spans + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/opentelemetry/types/otel_scope.py b/langfuse/api/opentelemetry/types/otel_scope.py new file mode 100644 index 000000000..7e12a16a3 --- /dev/null +++ b/langfuse/api/opentelemetry/types/otel_scope.py @@ -0,0 +1,41 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .otel_attribute import OtelAttribute + + +class OtelScope(UniversalBaseModel): + """ + Instrumentation scope information + """ + + name: typing.Optional[str] = pydantic.Field(default=None) + """ + Instrumentation scope name + """ + + version: typing.Optional[str] = pydantic.Field(default=None) + """ + Instrumentation scope version + """ + + attributes: typing.Optional[typing.List[OtelAttribute]] = pydantic.Field( + default=None + ) + """ + Additional scope attributes + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/opentelemetry/types/otel_scope_span.py b/langfuse/api/opentelemetry/types/otel_scope_span.py new file mode 100644 index 000000000..57179fa23 --- /dev/null +++ b/langfuse/api/opentelemetry/types/otel_scope_span.py @@ -0,0 +1,35 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .otel_scope import OtelScope +from .otel_span import OtelSpan + + +class OtelScopeSpan(UniversalBaseModel): + """ + Collection of spans from a single instrumentation scope + """ + + scope: typing.Optional[OtelScope] = pydantic.Field(default=None) + """ + Instrumentation scope information + """ + + spans: typing.Optional[typing.List[OtelSpan]] = pydantic.Field(default=None) + """ + Array of spans + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/opentelemetry/types/otel_span.py b/langfuse/api/opentelemetry/types/otel_span.py new file mode 100644 index 000000000..9d5ab14e0 --- /dev/null +++ b/langfuse/api/opentelemetry/types/otel_span.py @@ -0,0 +1,83 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .otel_attribute import OtelAttribute + + +class OtelSpan(UniversalBaseModel): + """ + Individual span representing a unit of work or operation + """ + + trace_id: typing_extensions.Annotated[ + typing.Optional[typing.Any], FieldMetadata(alias="traceId") + ] = pydantic.Field(default=None) + """ + Trace ID (16 bytes, hex-encoded string in JSON or Buffer in binary) + """ + + span_id: typing_extensions.Annotated[ + typing.Optional[typing.Any], FieldMetadata(alias="spanId") + ] = pydantic.Field(default=None) + """ + Span ID (8 bytes, hex-encoded string in JSON or Buffer in binary) + """ + + parent_span_id: typing_extensions.Annotated[ + typing.Optional[typing.Any], FieldMetadata(alias="parentSpanId") + ] = pydantic.Field(default=None) + """ + Parent span ID if this is a child span + """ + + name: typing.Optional[str] = pydantic.Field(default=None) + """ + Span name describing the operation + """ + + kind: typing.Optional[int] = pydantic.Field(default=None) + """ + Span kind (1=INTERNAL, 2=SERVER, 3=CLIENT, 4=PRODUCER, 5=CONSUMER) + """ + + start_time_unix_nano: typing_extensions.Annotated[ + typing.Optional[typing.Any], FieldMetadata(alias="startTimeUnixNano") + ] = pydantic.Field(default=None) + """ + Start time in nanoseconds since Unix epoch + """ + + end_time_unix_nano: typing_extensions.Annotated[ + typing.Optional[typing.Any], FieldMetadata(alias="endTimeUnixNano") + ] = pydantic.Field(default=None) + """ + End time in nanoseconds since Unix epoch + """ + + attributes: typing.Optional[typing.List[OtelAttribute]] = pydantic.Field( + default=None + ) + """ + Span attributes including Langfuse-specific attributes (langfuse.observation.*) + """ + + status: typing.Optional[typing.Any] = pydantic.Field(default=None) + """ + Span status object + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/opentelemetry/types/otel_trace_response.py b/langfuse/api/opentelemetry/types/otel_trace_response.py new file mode 100644 index 000000000..5c21cbe7a --- /dev/null +++ b/langfuse/api/opentelemetry/types/otel_trace_response.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class OtelTraceResponse(UniversalBaseModel): + """ + Response from trace export request. Empty object indicates success. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/organizations/__init__.py b/langfuse/api/organizations/__init__.py new file mode 100644 index 000000000..469d10a42 --- /dev/null +++ b/langfuse/api/organizations/__init__.py @@ -0,0 +1,73 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + DeleteMembershipRequest, + MembershipDeletionResponse, + MembershipRequest, + MembershipResponse, + MembershipRole, + MembershipsResponse, + OrganizationApiKey, + OrganizationApiKeysResponse, + OrganizationProject, + OrganizationProjectsResponse, + ) +_dynamic_imports: typing.Dict[str, str] = { + "DeleteMembershipRequest": ".types", + "MembershipDeletionResponse": ".types", + "MembershipRequest": ".types", + "MembershipResponse": ".types", + "MembershipRole": ".types", + "MembershipsResponse": ".types", + "OrganizationApiKey": ".types", + "OrganizationApiKeysResponse": ".types", + "OrganizationProject": ".types", + "OrganizationProjectsResponse": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "DeleteMembershipRequest", + "MembershipDeletionResponse", + "MembershipRequest", + "MembershipResponse", + "MembershipRole", + "MembershipsResponse", + "OrganizationApiKey", + "OrganizationApiKeysResponse", + "OrganizationProject", + "OrganizationProjectsResponse", +] diff --git a/langfuse/api/organizations/client.py b/langfuse/api/organizations/client.py new file mode 100644 index 000000000..e49d8106d --- /dev/null +++ b/langfuse/api/organizations/client.py @@ -0,0 +1,752 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawOrganizationsClient, RawOrganizationsClient +from .types.membership_deletion_response import MembershipDeletionResponse +from .types.membership_response import MembershipResponse +from .types.membership_role import MembershipRole +from .types.memberships_response import MembershipsResponse +from .types.organization_api_keys_response import OrganizationApiKeysResponse +from .types.organization_projects_response import OrganizationProjectsResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class OrganizationsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawOrganizationsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawOrganizationsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawOrganizationsClient + """ + return self._raw_client + + def get_organization_memberships( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> MembershipsResponse: + """ + Get all memberships for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipsResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.organizations.get_organization_memberships() + """ + _response = self._raw_client.get_organization_memberships( + request_options=request_options + ) + return _response.data + + def update_organization_membership( + self, + *, + user_id: str, + role: MembershipRole, + request_options: typing.Optional[RequestOptions] = None, + ) -> MembershipResponse: + """ + Create or update a membership for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + role : MembershipRole + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.organizations.update_organization_membership( + user_id="userId", + role="OWNER", + ) + """ + _response = self._raw_client.update_organization_membership( + user_id=user_id, role=role, request_options=request_options + ) + return _response.data + + def delete_organization_membership( + self, *, user_id: str, request_options: typing.Optional[RequestOptions] = None + ) -> MembershipDeletionResponse: + """ + Delete a membership from the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipDeletionResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.organizations.delete_organization_membership( + user_id="userId", + ) + """ + _response = self._raw_client.delete_organization_membership( + user_id=user_id, request_options=request_options + ) + return _response.data + + def get_project_memberships( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> MembershipsResponse: + """ + Get all memberships for a specific project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipsResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.organizations.get_project_memberships( + project_id="projectId", + ) + """ + _response = self._raw_client.get_project_memberships( + project_id, request_options=request_options + ) + return _response.data + + def update_project_membership( + self, + project_id: str, + *, + user_id: str, + role: MembershipRole, + request_options: typing.Optional[RequestOptions] = None, + ) -> MembershipResponse: + """ + Create or update a membership for a specific project (requires organization-scoped API key). The user must already be a member of the organization. + + Parameters + ---------- + project_id : str + + user_id : str + + role : MembershipRole + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.organizations.update_project_membership( + project_id="projectId", + user_id="userId", + role="OWNER", + ) + """ + _response = self._raw_client.update_project_membership( + project_id, user_id=user_id, role=role, request_options=request_options + ) + return _response.data + + def delete_project_membership( + self, + project_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> MembershipDeletionResponse: + """ + Delete a membership from a specific project (requires organization-scoped API key). The user must be a member of the organization. + + Parameters + ---------- + project_id : str + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipDeletionResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.organizations.delete_project_membership( + project_id="projectId", + user_id="userId", + ) + """ + _response = self._raw_client.delete_project_membership( + project_id, user_id=user_id, request_options=request_options + ) + return _response.data + + def get_organization_projects( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> OrganizationProjectsResponse: + """ + Get all projects for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationProjectsResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.organizations.get_organization_projects() + """ + _response = self._raw_client.get_organization_projects( + request_options=request_options + ) + return _response.data + + def get_organization_api_keys( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> OrganizationApiKeysResponse: + """ + Get all API keys for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationApiKeysResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.organizations.get_organization_api_keys() + """ + _response = self._raw_client.get_organization_api_keys( + request_options=request_options + ) + return _response.data + + +class AsyncOrganizationsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawOrganizationsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawOrganizationsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawOrganizationsClient + """ + return self._raw_client + + async def get_organization_memberships( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> MembershipsResponse: + """ + Get all memberships for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipsResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.organizations.get_organization_memberships() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_organization_memberships( + request_options=request_options + ) + return _response.data + + async def update_organization_membership( + self, + *, + user_id: str, + role: MembershipRole, + request_options: typing.Optional[RequestOptions] = None, + ) -> MembershipResponse: + """ + Create or update a membership for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + role : MembershipRole + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.organizations.update_organization_membership( + user_id="userId", + role="OWNER", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.update_organization_membership( + user_id=user_id, role=role, request_options=request_options + ) + return _response.data + + async def delete_organization_membership( + self, *, user_id: str, request_options: typing.Optional[RequestOptions] = None + ) -> MembershipDeletionResponse: + """ + Delete a membership from the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipDeletionResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.organizations.delete_organization_membership( + user_id="userId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete_organization_membership( + user_id=user_id, request_options=request_options + ) + return _response.data + + async def get_project_memberships( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> MembershipsResponse: + """ + Get all memberships for a specific project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipsResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.organizations.get_project_memberships( + project_id="projectId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_project_memberships( + project_id, request_options=request_options + ) + return _response.data + + async def update_project_membership( + self, + project_id: str, + *, + user_id: str, + role: MembershipRole, + request_options: typing.Optional[RequestOptions] = None, + ) -> MembershipResponse: + """ + Create or update a membership for a specific project (requires organization-scoped API key). The user must already be a member of the organization. + + Parameters + ---------- + project_id : str + + user_id : str + + role : MembershipRole + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.organizations.update_project_membership( + project_id="projectId", + user_id="userId", + role="OWNER", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.update_project_membership( + project_id, user_id=user_id, role=role, request_options=request_options + ) + return _response.data + + async def delete_project_membership( + self, + project_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> MembershipDeletionResponse: + """ + Delete a membership from a specific project (requires organization-scoped API key). The user must be a member of the organization. + + Parameters + ---------- + project_id : str + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MembershipDeletionResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.organizations.delete_project_membership( + project_id="projectId", + user_id="userId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete_project_membership( + project_id, user_id=user_id, request_options=request_options + ) + return _response.data + + async def get_organization_projects( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> OrganizationProjectsResponse: + """ + Get all projects for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationProjectsResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.organizations.get_organization_projects() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_organization_projects( + request_options=request_options + ) + return _response.data + + async def get_organization_api_keys( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> OrganizationApiKeysResponse: + """ + Get all API keys for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + OrganizationApiKeysResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.organizations.get_organization_api_keys() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_organization_api_keys( + request_options=request_options + ) + return _response.data diff --git a/langfuse/api/organizations/raw_client.py b/langfuse/api/organizations/raw_client.py new file mode 100644 index 000000000..89596e8bf --- /dev/null +++ b/langfuse/api/organizations/raw_client.py @@ -0,0 +1,1707 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.membership_deletion_response import MembershipDeletionResponse +from .types.membership_response import MembershipResponse +from .types.membership_role import MembershipRole +from .types.memberships_response import MembershipsResponse +from .types.organization_api_keys_response import OrganizationApiKeysResponse +from .types.organization_projects_response import OrganizationProjectsResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawOrganizationsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get_organization_memberships( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[MembershipsResponse]: + """ + Get all memberships for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[MembershipsResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/organizations/memberships", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipsResponse, + parse_obj_as( + type_=MembershipsResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def update_organization_membership( + self, + *, + user_id: str, + role: MembershipRole, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[MembershipResponse]: + """ + Create or update a membership for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + role : MembershipRole + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[MembershipResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/organizations/memberships", + method="PUT", + json={ + "userId": user_id, + "role": role, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipResponse, + parse_obj_as( + type_=MembershipResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete_organization_membership( + self, *, user_id: str, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[MembershipDeletionResponse]: + """ + Delete a membership from the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[MembershipDeletionResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/organizations/memberships", + method="DELETE", + json={ + "userId": user_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipDeletionResponse, + parse_obj_as( + type_=MembershipDeletionResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_project_memberships( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[MembershipsResponse]: + """ + Get all memberships for a specific project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[MembershipsResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/memberships", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipsResponse, + parse_obj_as( + type_=MembershipsResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def update_project_membership( + self, + project_id: str, + *, + user_id: str, + role: MembershipRole, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[MembershipResponse]: + """ + Create or update a membership for a specific project (requires organization-scoped API key). The user must already be a member of the organization. + + Parameters + ---------- + project_id : str + + user_id : str + + role : MembershipRole + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[MembershipResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/memberships", + method="PUT", + json={ + "userId": user_id, + "role": role, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipResponse, + parse_obj_as( + type_=MembershipResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete_project_membership( + self, + project_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[MembershipDeletionResponse]: + """ + Delete a membership from a specific project (requires organization-scoped API key). The user must be a member of the organization. + + Parameters + ---------- + project_id : str + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[MembershipDeletionResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/memberships", + method="DELETE", + json={ + "userId": user_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipDeletionResponse, + parse_obj_as( + type_=MembershipDeletionResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_organization_projects( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[OrganizationProjectsResponse]: + """ + Get all projects for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[OrganizationProjectsResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/organizations/projects", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + OrganizationProjectsResponse, + parse_obj_as( + type_=OrganizationProjectsResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_organization_api_keys( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[OrganizationApiKeysResponse]: + """ + Get all API keys for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[OrganizationApiKeysResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/organizations/apiKeys", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + OrganizationApiKeysResponse, + parse_obj_as( + type_=OrganizationApiKeysResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawOrganizationsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get_organization_memberships( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[MembershipsResponse]: + """ + Get all memberships for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[MembershipsResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/organizations/memberships", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipsResponse, + parse_obj_as( + type_=MembershipsResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def update_organization_membership( + self, + *, + user_id: str, + role: MembershipRole, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[MembershipResponse]: + """ + Create or update a membership for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + role : MembershipRole + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[MembershipResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/organizations/memberships", + method="PUT", + json={ + "userId": user_id, + "role": role, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipResponse, + parse_obj_as( + type_=MembershipResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete_organization_membership( + self, *, user_id: str, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[MembershipDeletionResponse]: + """ + Delete a membership from the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[MembershipDeletionResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/organizations/memberships", + method="DELETE", + json={ + "userId": user_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipDeletionResponse, + parse_obj_as( + type_=MembershipDeletionResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_project_memberships( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[MembershipsResponse]: + """ + Get all memberships for a specific project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[MembershipsResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/memberships", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipsResponse, + parse_obj_as( + type_=MembershipsResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def update_project_membership( + self, + project_id: str, + *, + user_id: str, + role: MembershipRole, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[MembershipResponse]: + """ + Create or update a membership for a specific project (requires organization-scoped API key). The user must already be a member of the organization. + + Parameters + ---------- + project_id : str + + user_id : str + + role : MembershipRole + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[MembershipResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/memberships", + method="PUT", + json={ + "userId": user_id, + "role": role, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipResponse, + parse_obj_as( + type_=MembershipResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete_project_membership( + self, + project_id: str, + *, + user_id: str, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[MembershipDeletionResponse]: + """ + Delete a membership from a specific project (requires organization-scoped API key). The user must be a member of the organization. + + Parameters + ---------- + project_id : str + + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[MembershipDeletionResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/memberships", + method="DELETE", + json={ + "userId": user_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MembershipDeletionResponse, + parse_obj_as( + type_=MembershipDeletionResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_organization_projects( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[OrganizationProjectsResponse]: + """ + Get all projects for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[OrganizationProjectsResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/organizations/projects", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + OrganizationProjectsResponse, + parse_obj_as( + type_=OrganizationProjectsResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_organization_api_keys( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[OrganizationApiKeysResponse]: + """ + Get all API keys for the organization associated with the API key (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[OrganizationApiKeysResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/organizations/apiKeys", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + OrganizationApiKeysResponse, + parse_obj_as( + type_=OrganizationApiKeysResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/organizations/types/__init__.py b/langfuse/api/organizations/types/__init__.py new file mode 100644 index 000000000..2ac6cb3e7 --- /dev/null +++ b/langfuse/api/organizations/types/__init__.py @@ -0,0 +1,71 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .delete_membership_request import DeleteMembershipRequest + from .membership_deletion_response import MembershipDeletionResponse + from .membership_request import MembershipRequest + from .membership_response import MembershipResponse + from .membership_role import MembershipRole + from .memberships_response import MembershipsResponse + from .organization_api_key import OrganizationApiKey + from .organization_api_keys_response import OrganizationApiKeysResponse + from .organization_project import OrganizationProject + from .organization_projects_response import OrganizationProjectsResponse +_dynamic_imports: typing.Dict[str, str] = { + "DeleteMembershipRequest": ".delete_membership_request", + "MembershipDeletionResponse": ".membership_deletion_response", + "MembershipRequest": ".membership_request", + "MembershipResponse": ".membership_response", + "MembershipRole": ".membership_role", + "MembershipsResponse": ".memberships_response", + "OrganizationApiKey": ".organization_api_key", + "OrganizationApiKeysResponse": ".organization_api_keys_response", + "OrganizationProject": ".organization_project", + "OrganizationProjectsResponse": ".organization_projects_response", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "DeleteMembershipRequest", + "MembershipDeletionResponse", + "MembershipRequest", + "MembershipResponse", + "MembershipRole", + "MembershipsResponse", + "OrganizationApiKey", + "OrganizationApiKeysResponse", + "OrganizationProject", + "OrganizationProjectsResponse", +] diff --git a/langfuse/api/organizations/types/delete_membership_request.py b/langfuse/api/organizations/types/delete_membership_request.py new file mode 100644 index 000000000..3e4d4d24b --- /dev/null +++ b/langfuse/api/organizations/types/delete_membership_request.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class DeleteMembershipRequest(UniversalBaseModel): + user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/organizations/types/membership_deletion_response.py b/langfuse/api/organizations/types/membership_deletion_response.py new file mode 100644 index 000000000..bff8dbca0 --- /dev/null +++ b/langfuse/api/organizations/types/membership_deletion_response.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class MembershipDeletionResponse(UniversalBaseModel): + message: str + user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/organizations/types/membership_request.py b/langfuse/api/organizations/types/membership_request.py new file mode 100644 index 000000000..d4b88b35e --- /dev/null +++ b/langfuse/api/organizations/types/membership_request.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .membership_role import MembershipRole + + +class MembershipRequest(UniversalBaseModel): + user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] + role: MembershipRole + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/organizations/types/membership_response.py b/langfuse/api/organizations/types/membership_response.py new file mode 100644 index 000000000..456b0b53b --- /dev/null +++ b/langfuse/api/organizations/types/membership_response.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .membership_role import MembershipRole + + +class MembershipResponse(UniversalBaseModel): + user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] + role: MembershipRole + email: str + name: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/organizations/types/membership_role.py b/langfuse/api/organizations/types/membership_role.py new file mode 100644 index 000000000..d7683b8d5 --- /dev/null +++ b/langfuse/api/organizations/types/membership_role.py @@ -0,0 +1,7 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +MembershipRole = typing.Union[ + typing.Literal["OWNER", "ADMIN", "MEMBER", "VIEWER"], typing.Any +] diff --git a/langfuse/api/organizations/types/memberships_response.py b/langfuse/api/organizations/types/memberships_response.py new file mode 100644 index 000000000..6238d90da --- /dev/null +++ b/langfuse/api/organizations/types/memberships_response.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .membership_response import MembershipResponse + + +class MembershipsResponse(UniversalBaseModel): + memberships: typing.List[MembershipResponse] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/organizations/types/organization_api_key.py b/langfuse/api/organizations/types/organization_api_key.py new file mode 100644 index 000000000..4989e3bd2 --- /dev/null +++ b/langfuse/api/organizations/types/organization_api_key.py @@ -0,0 +1,38 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class OrganizationApiKey(UniversalBaseModel): + id: str + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + expires_at: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="expiresAt") + ] = None + last_used_at: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="lastUsedAt") + ] = None + note: typing.Optional[str] = None + public_key: typing_extensions.Annotated[str, FieldMetadata(alias="publicKey")] + display_secret_key: typing_extensions.Annotated[ + str, FieldMetadata(alias="displaySecretKey") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/organizations/types/organization_api_keys_response.py b/langfuse/api/organizations/types/organization_api_keys_response.py new file mode 100644 index 000000000..ccca5129e --- /dev/null +++ b/langfuse/api/organizations/types/organization_api_keys_response.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .organization_api_key import OrganizationApiKey + + +class OrganizationApiKeysResponse(UniversalBaseModel): + api_keys: typing_extensions.Annotated[ + typing.List[OrganizationApiKey], FieldMetadata(alias="apiKeys") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/organizations/types/organization_project.py b/langfuse/api/organizations/types/organization_project.py new file mode 100644 index 000000000..f1847c2d1 --- /dev/null +++ b/langfuse/api/organizations/types/organization_project.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class OrganizationProject(UniversalBaseModel): + id: str + name: str + metadata: typing.Optional[typing.Dict[str, typing.Any]] = None + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/organizations/types/organization_projects_response.py b/langfuse/api/organizations/types/organization_projects_response.py new file mode 100644 index 000000000..ef10ed030 --- /dev/null +++ b/langfuse/api/organizations/types/organization_projects_response.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .organization_project import OrganizationProject + + +class OrganizationProjectsResponse(UniversalBaseModel): + projects: typing.List[OrganizationProject] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/projects/__init__.py b/langfuse/api/projects/__init__.py new file mode 100644 index 000000000..6cb87b5e2 --- /dev/null +++ b/langfuse/api/projects/__init__.py @@ -0,0 +1,64 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + ApiKeyDeletionResponse, + ApiKeyList, + ApiKeyResponse, + ApiKeySummary, + Project, + ProjectDeletionResponse, + Projects, + ) +_dynamic_imports: typing.Dict[str, str] = { + "ApiKeyDeletionResponse": ".types", + "ApiKeyList": ".types", + "ApiKeyResponse": ".types", + "ApiKeySummary": ".types", + "Project": ".types", + "ProjectDeletionResponse": ".types", + "Projects": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "ApiKeyDeletionResponse", + "ApiKeyList", + "ApiKeyResponse", + "ApiKeySummary", + "Project", + "ProjectDeletionResponse", + "Projects", +] diff --git a/langfuse/api/projects/client.py b/langfuse/api/projects/client.py new file mode 100644 index 000000000..238c29c1d --- /dev/null +++ b/langfuse/api/projects/client.py @@ -0,0 +1,756 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawProjectsClient, RawProjectsClient +from .types.api_key_deletion_response import ApiKeyDeletionResponse +from .types.api_key_list import ApiKeyList +from .types.api_key_response import ApiKeyResponse +from .types.project import Project +from .types.project_deletion_response import ProjectDeletionResponse +from .types.projects import Projects + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class ProjectsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawProjectsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawProjectsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawProjectsClient + """ + return self._raw_client + + def get( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> Projects: + """ + Get Project associated with API key (requires project-scoped API key). You can use GET /api/public/organizations/projects to get all projects with an organization-scoped key. + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Projects + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.projects.get() + """ + _response = self._raw_client.get(request_options=request_options) + return _response.data + + def create( + self, + *, + name: str, + retention: int, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Project: + """ + Create a new project (requires organization-scoped API key) + + Parameters + ---------- + name : str + + retention : int + Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + Optional metadata for the project + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Project + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.projects.create( + name="name", + retention=1, + ) + """ + _response = self._raw_client.create( + name=name, + retention=retention, + metadata=metadata, + request_options=request_options, + ) + return _response.data + + def update( + self, + project_id: str, + *, + name: str, + retention: int, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Project: + """ + Update a project by ID (requires organization-scoped API key). + + Parameters + ---------- + project_id : str + + name : str + + retention : int + Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + Optional metadata for the project + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Project + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.projects.update( + project_id="projectId", + name="name", + retention=1, + ) + """ + _response = self._raw_client.update( + project_id, + name=name, + retention=retention, + metadata=metadata, + request_options=request_options, + ) + return _response.data + + def delete( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> ProjectDeletionResponse: + """ + Delete a project by ID (requires organization-scoped API key). Project deletion is processed asynchronously. + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ProjectDeletionResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.projects.delete( + project_id="projectId", + ) + """ + _response = self._raw_client.delete(project_id, request_options=request_options) + return _response.data + + def get_api_keys( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> ApiKeyList: + """ + Get all API keys for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ApiKeyList + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.projects.get_api_keys( + project_id="projectId", + ) + """ + _response = self._raw_client.get_api_keys( + project_id, request_options=request_options + ) + return _response.data + + def create_api_key( + self, + project_id: str, + *, + note: typing.Optional[str] = OMIT, + public_key: typing.Optional[str] = OMIT, + secret_key: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> ApiKeyResponse: + """ + Create a new API key for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + note : typing.Optional[str] + Optional note for the API key + + public_key : typing.Optional[str] + Optional predefined public key. Must start with 'pk-lf-'. If provided, secretKey must also be provided. + + secret_key : typing.Optional[str] + Optional predefined secret key. Must start with 'sk-lf-'. If provided, publicKey must also be provided. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ApiKeyResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.projects.create_api_key( + project_id="projectId", + ) + """ + _response = self._raw_client.create_api_key( + project_id, + note=note, + public_key=public_key, + secret_key=secret_key, + request_options=request_options, + ) + return _response.data + + def delete_api_key( + self, + project_id: str, + api_key_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> ApiKeyDeletionResponse: + """ + Delete an API key for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + api_key_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ApiKeyDeletionResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.projects.delete_api_key( + project_id="projectId", + api_key_id="apiKeyId", + ) + """ + _response = self._raw_client.delete_api_key( + project_id, api_key_id, request_options=request_options + ) + return _response.data + + +class AsyncProjectsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawProjectsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawProjectsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawProjectsClient + """ + return self._raw_client + + async def get( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> Projects: + """ + Get Project associated with API key (requires project-scoped API key). You can use GET /api/public/organizations/projects to get all projects with an organization-scoped key. + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Projects + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.projects.get() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get(request_options=request_options) + return _response.data + + async def create( + self, + *, + name: str, + retention: int, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Project: + """ + Create a new project (requires organization-scoped API key) + + Parameters + ---------- + name : str + + retention : int + Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + Optional metadata for the project + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Project + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.projects.create( + name="name", + retention=1, + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create( + name=name, + retention=retention, + metadata=metadata, + request_options=request_options, + ) + return _response.data + + async def update( + self, + project_id: str, + *, + name: str, + retention: int, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> Project: + """ + Update a project by ID (requires organization-scoped API key). + + Parameters + ---------- + project_id : str + + name : str + + retention : int + Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + Optional metadata for the project + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Project + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.projects.update( + project_id="projectId", + name="name", + retention=1, + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.update( + project_id, + name=name, + retention=retention, + metadata=metadata, + request_options=request_options, + ) + return _response.data + + async def delete( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> ProjectDeletionResponse: + """ + Delete a project by ID (requires organization-scoped API key). Project deletion is processed asynchronously. + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ProjectDeletionResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.projects.delete( + project_id="projectId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete( + project_id, request_options=request_options + ) + return _response.data + + async def get_api_keys( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> ApiKeyList: + """ + Get all API keys for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ApiKeyList + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.projects.get_api_keys( + project_id="projectId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_api_keys( + project_id, request_options=request_options + ) + return _response.data + + async def create_api_key( + self, + project_id: str, + *, + note: typing.Optional[str] = OMIT, + public_key: typing.Optional[str] = OMIT, + secret_key: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> ApiKeyResponse: + """ + Create a new API key for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + note : typing.Optional[str] + Optional note for the API key + + public_key : typing.Optional[str] + Optional predefined public key. Must start with 'pk-lf-'. If provided, secretKey must also be provided. + + secret_key : typing.Optional[str] + Optional predefined secret key. Must start with 'sk-lf-'. If provided, publicKey must also be provided. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ApiKeyResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.projects.create_api_key( + project_id="projectId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create_api_key( + project_id, + note=note, + public_key=public_key, + secret_key=secret_key, + request_options=request_options, + ) + return _response.data + + async def delete_api_key( + self, + project_id: str, + api_key_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> ApiKeyDeletionResponse: + """ + Delete an API key for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + api_key_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ApiKeyDeletionResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.projects.delete_api_key( + project_id="projectId", + api_key_id="apiKeyId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete_api_key( + project_id, api_key_id, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/projects/raw_client.py b/langfuse/api/projects/raw_client.py new file mode 100644 index 000000000..a5c2218e6 --- /dev/null +++ b/langfuse/api/projects/raw_client.py @@ -0,0 +1,1571 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.api_key_deletion_response import ApiKeyDeletionResponse +from .types.api_key_list import ApiKeyList +from .types.api_key_response import ApiKeyResponse +from .types.project import Project +from .types.project_deletion_response import ProjectDeletionResponse +from .types.projects import Projects + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawProjectsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[Projects]: + """ + Get Project associated with API key (requires project-scoped API key). You can use GET /api/public/organizations/projects to get all projects with an organization-scoped key. + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Projects] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/projects", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Projects, + parse_obj_as( + type_=Projects, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def create( + self, + *, + name: str, + retention: int, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Project]: + """ + Create a new project (requires organization-scoped API key) + + Parameters + ---------- + name : str + + retention : int + Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + Optional metadata for the project + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Project] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/projects", + method="POST", + json={ + "name": name, + "metadata": metadata, + "retention": retention, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Project, + parse_obj_as( + type_=Project, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def update( + self, + project_id: str, + *, + name: str, + retention: int, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Project]: + """ + Update a project by ID (requires organization-scoped API key). + + Parameters + ---------- + project_id : str + + name : str + + retention : int + Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + Optional metadata for the project + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Project] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}", + method="PUT", + json={ + "name": name, + "metadata": metadata, + "retention": retention, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Project, + parse_obj_as( + type_=Project, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ProjectDeletionResponse]: + """ + Delete a project by ID (requires organization-scoped API key). Project deletion is processed asynchronously. + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ProjectDeletionResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ProjectDeletionResponse, + parse_obj_as( + type_=ProjectDeletionResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_api_keys( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ApiKeyList]: + """ + Get all API keys for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ApiKeyList] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ApiKeyList, + parse_obj_as( + type_=ApiKeyList, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def create_api_key( + self, + project_id: str, + *, + note: typing.Optional[str] = OMIT, + public_key: typing.Optional[str] = OMIT, + secret_key: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ApiKeyResponse]: + """ + Create a new API key for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + note : typing.Optional[str] + Optional note for the API key + + public_key : typing.Optional[str] + Optional predefined public key. Must start with 'pk-lf-'. If provided, secretKey must also be provided. + + secret_key : typing.Optional[str] + Optional predefined secret key. Must start with 'sk-lf-'. If provided, publicKey must also be provided. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ApiKeyResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys", + method="POST", + json={ + "note": note, + "publicKey": public_key, + "secretKey": secret_key, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ApiKeyResponse, + parse_obj_as( + type_=ApiKeyResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete_api_key( + self, + project_id: str, + api_key_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ApiKeyDeletionResponse]: + """ + Delete an API key for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + api_key_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ApiKeyDeletionResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys/{jsonable_encoder(api_key_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ApiKeyDeletionResponse, + parse_obj_as( + type_=ApiKeyDeletionResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawProjectsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[Projects]: + """ + Get Project associated with API key (requires project-scoped API key). You can use GET /api/public/organizations/projects to get all projects with an organization-scoped key. + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Projects] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/projects", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Projects, + parse_obj_as( + type_=Projects, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def create( + self, + *, + name: str, + retention: int, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Project]: + """ + Create a new project (requires organization-scoped API key) + + Parameters + ---------- + name : str + + retention : int + Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + Optional metadata for the project + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Project] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/projects", + method="POST", + json={ + "name": name, + "metadata": metadata, + "retention": retention, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Project, + parse_obj_as( + type_=Project, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def update( + self, + project_id: str, + *, + name: str, + retention: int, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Project]: + """ + Update a project by ID (requires organization-scoped API key). + + Parameters + ---------- + project_id : str + + name : str + + retention : int + Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + Optional metadata for the project + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Project] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}", + method="PUT", + json={ + "name": name, + "metadata": metadata, + "retention": retention, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Project, + parse_obj_as( + type_=Project, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ProjectDeletionResponse]: + """ + Delete a project by ID (requires organization-scoped API key). Project deletion is processed asynchronously. + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ProjectDeletionResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ProjectDeletionResponse, + parse_obj_as( + type_=ProjectDeletionResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_api_keys( + self, + project_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ApiKeyList]: + """ + Get all API keys for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ApiKeyList] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ApiKeyList, + parse_obj_as( + type_=ApiKeyList, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def create_api_key( + self, + project_id: str, + *, + note: typing.Optional[str] = OMIT, + public_key: typing.Optional[str] = OMIT, + secret_key: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ApiKeyResponse]: + """ + Create a new API key for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + note : typing.Optional[str] + Optional note for the API key + + public_key : typing.Optional[str] + Optional predefined public key. Must start with 'pk-lf-'. If provided, secretKey must also be provided. + + secret_key : typing.Optional[str] + Optional predefined secret key. Must start with 'sk-lf-'. If provided, publicKey must also be provided. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ApiKeyResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys", + method="POST", + json={ + "note": note, + "publicKey": public_key, + "secretKey": secret_key, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ApiKeyResponse, + parse_obj_as( + type_=ApiKeyResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete_api_key( + self, + project_id: str, + api_key_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ApiKeyDeletionResponse]: + """ + Delete an API key for a project (requires organization-scoped API key) + + Parameters + ---------- + project_id : str + + api_key_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ApiKeyDeletionResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys/{jsonable_encoder(api_key_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ApiKeyDeletionResponse, + parse_obj_as( + type_=ApiKeyDeletionResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/projects/types/__init__.py b/langfuse/api/projects/types/__init__.py new file mode 100644 index 000000000..e336c1ebb --- /dev/null +++ b/langfuse/api/projects/types/__init__.py @@ -0,0 +1,62 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .api_key_deletion_response import ApiKeyDeletionResponse + from .api_key_list import ApiKeyList + from .api_key_response import ApiKeyResponse + from .api_key_summary import ApiKeySummary + from .project import Project + from .project_deletion_response import ProjectDeletionResponse + from .projects import Projects +_dynamic_imports: typing.Dict[str, str] = { + "ApiKeyDeletionResponse": ".api_key_deletion_response", + "ApiKeyList": ".api_key_list", + "ApiKeyResponse": ".api_key_response", + "ApiKeySummary": ".api_key_summary", + "Project": ".project", + "ProjectDeletionResponse": ".project_deletion_response", + "Projects": ".projects", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "ApiKeyDeletionResponse", + "ApiKeyList", + "ApiKeyResponse", + "ApiKeySummary", + "Project", + "ProjectDeletionResponse", + "Projects", +] diff --git a/langfuse/api/projects/types/api_key_deletion_response.py b/langfuse/api/projects/types/api_key_deletion_response.py new file mode 100644 index 000000000..ffbaf27c8 --- /dev/null +++ b/langfuse/api/projects/types/api_key_deletion_response.py @@ -0,0 +1,25 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ApiKeyDeletionResponse(UniversalBaseModel): + """ + Response for API key deletion + """ + + success: bool + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/projects/types/api_key_list.py b/langfuse/api/projects/types/api_key_list.py new file mode 100644 index 000000000..d6bb6b09e --- /dev/null +++ b/langfuse/api/projects/types/api_key_list.py @@ -0,0 +1,30 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .api_key_summary import ApiKeySummary + + +class ApiKeyList(UniversalBaseModel): + """ + List of API keys for a project + """ + + api_keys: typing_extensions.Annotated[ + typing.List[ApiKeySummary], FieldMetadata(alias="apiKeys") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/projects/types/api_key_response.py b/langfuse/api/projects/types/api_key_response.py new file mode 100644 index 000000000..19b751cd7 --- /dev/null +++ b/langfuse/api/projects/types/api_key_response.py @@ -0,0 +1,37 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class ApiKeyResponse(UniversalBaseModel): + """ + Response for API key creation + """ + + id: str + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + public_key: typing_extensions.Annotated[str, FieldMetadata(alias="publicKey")] + secret_key: typing_extensions.Annotated[str, FieldMetadata(alias="secretKey")] + display_secret_key: typing_extensions.Annotated[ + str, FieldMetadata(alias="displaySecretKey") + ] + note: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/projects/types/api_key_summary.py b/langfuse/api/projects/types/api_key_summary.py new file mode 100644 index 000000000..4ab1173c3 --- /dev/null +++ b/langfuse/api/projects/types/api_key_summary.py @@ -0,0 +1,42 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class ApiKeySummary(UniversalBaseModel): + """ + Summary of an API key + """ + + id: str + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + expires_at: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="expiresAt") + ] = None + last_used_at: typing_extensions.Annotated[ + typing.Optional[dt.datetime], FieldMetadata(alias="lastUsedAt") + ] = None + note: typing.Optional[str] = None + public_key: typing_extensions.Annotated[str, FieldMetadata(alias="publicKey")] + display_secret_key: typing_extensions.Annotated[ + str, FieldMetadata(alias="displaySecretKey") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/projects/types/project.py b/langfuse/api/projects/types/project.py new file mode 100644 index 000000000..b52b53e58 --- /dev/null +++ b/langfuse/api/projects/types/project.py @@ -0,0 +1,35 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class Project(UniversalBaseModel): + id: str + name: str + metadata: typing.Dict[str, typing.Any] = pydantic.Field() + """ + Metadata for the project + """ + + retention_days: typing_extensions.Annotated[ + typing.Optional[int], FieldMetadata(alias="retentionDays") + ] = pydantic.Field(default=None) + """ + Number of days to retain data. Null or 0 means no retention. Omitted if no retention is configured. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/projects/types/project_deletion_response.py b/langfuse/api/projects/types/project_deletion_response.py new file mode 100644 index 000000000..bccd5440b --- /dev/null +++ b/langfuse/api/projects/types/project_deletion_response.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ProjectDeletionResponse(UniversalBaseModel): + success: bool + message: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/projects/types/projects.py b/langfuse/api/projects/types/projects.py new file mode 100644 index 000000000..10ce03135 --- /dev/null +++ b/langfuse/api/projects/types/projects.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .project import Project + + +class Projects(UniversalBaseModel): + data: typing.List[Project] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/resources/prompt_version/__init__.py b/langfuse/api/prompt_version/__init__.py similarity index 76% rename from langfuse/api/resources/prompt_version/__init__.py rename to langfuse/api/prompt_version/__init__.py index f3ea2659b..5cde0202d 100644 --- a/langfuse/api/resources/prompt_version/__init__.py +++ b/langfuse/api/prompt_version/__init__.py @@ -1,2 +1,4 @@ # This file was auto-generated by Fern from our API Definition. +# isort: skip_file + diff --git a/langfuse/api/prompt_version/client.py b/langfuse/api/prompt_version/client.py new file mode 100644 index 000000000..f212447a4 --- /dev/null +++ b/langfuse/api/prompt_version/client.py @@ -0,0 +1,157 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from ..prompts.types.prompt import Prompt +from .raw_client import AsyncRawPromptVersionClient, RawPromptVersionClient + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class PromptVersionClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawPromptVersionClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawPromptVersionClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawPromptVersionClient + """ + return self._raw_client + + def update( + self, + name: str, + version: int, + *, + new_labels: typing.Sequence[str], + request_options: typing.Optional[RequestOptions] = None, + ) -> Prompt: + """ + Update labels for a specific prompt version + + Parameters + ---------- + name : str + The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), + the folder path must be URL encoded. + + version : int + Version of the prompt to update + + new_labels : typing.Sequence[str] + New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Prompt + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.prompt_version.update( + name="name", + version=1, + new_labels=["newLabels", "newLabels"], + ) + """ + _response = self._raw_client.update( + name, version, new_labels=new_labels, request_options=request_options + ) + return _response.data + + +class AsyncPromptVersionClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawPromptVersionClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawPromptVersionClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawPromptVersionClient + """ + return self._raw_client + + async def update( + self, + name: str, + version: int, + *, + new_labels: typing.Sequence[str], + request_options: typing.Optional[RequestOptions] = None, + ) -> Prompt: + """ + Update labels for a specific prompt version + + Parameters + ---------- + name : str + The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), + the folder path must be URL encoded. + + version : int + Version of the prompt to update + + new_labels : typing.Sequence[str] + New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Prompt + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.prompt_version.update( + name="name", + version=1, + new_labels=["newLabels", "newLabels"], + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.update( + name, version, new_labels=new_labels, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/prompt_version/raw_client.py b/langfuse/api/prompt_version/raw_client.py new file mode 100644 index 000000000..7d1e8d3f2 --- /dev/null +++ b/langfuse/api/prompt_version/raw_client.py @@ -0,0 +1,264 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from ..prompts.types.prompt import Prompt + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawPromptVersionClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def update( + self, + name: str, + version: int, + *, + new_labels: typing.Sequence[str], + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Prompt]: + """ + Update labels for a specific prompt version + + Parameters + ---------- + name : str + The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), + the folder path must be URL encoded. + + version : int + Version of the prompt to update + + new_labels : typing.Sequence[str] + New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Prompt] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/v2/prompts/{jsonable_encoder(name)}/versions/{jsonable_encoder(version)}", + method="PATCH", + json={ + "newLabels": new_labels, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Prompt, + parse_obj_as( + type_=Prompt, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawPromptVersionClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def update( + self, + name: str, + version: int, + *, + new_labels: typing.Sequence[str], + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Prompt]: + """ + Update labels for a specific prompt version + + Parameters + ---------- + name : str + The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), + the folder path must be URL encoded. + + version : int + Version of the prompt to update + + new_labels : typing.Sequence[str] + New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Prompt] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/v2/prompts/{jsonable_encoder(name)}/versions/{jsonable_encoder(version)}", + method="PATCH", + json={ + "newLabels": new_labels, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Prompt, + parse_obj_as( + type_=Prompt, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/prompts/__init__.py b/langfuse/api/prompts/__init__.py new file mode 100644 index 000000000..e310c0193 --- /dev/null +++ b/langfuse/api/prompts/__init__.py @@ -0,0 +1,100 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + BasePrompt, + ChatMessage, + ChatMessageWithPlaceholders, + ChatMessageWithPlaceholders_Chatmessage, + ChatMessageWithPlaceholders_Placeholder, + ChatPrompt, + CreateChatPromptRequest, + CreatePromptRequest, + CreatePromptRequest_Chat, + CreatePromptRequest_Text, + CreateTextPromptRequest, + PlaceholderMessage, + Prompt, + PromptMeta, + PromptMetaListResponse, + PromptType, + Prompt_Chat, + Prompt_Text, + TextPrompt, + ) +_dynamic_imports: typing.Dict[str, str] = { + "BasePrompt": ".types", + "ChatMessage": ".types", + "ChatMessageWithPlaceholders": ".types", + "ChatMessageWithPlaceholders_Chatmessage": ".types", + "ChatMessageWithPlaceholders_Placeholder": ".types", + "ChatPrompt": ".types", + "CreateChatPromptRequest": ".types", + "CreatePromptRequest": ".types", + "CreatePromptRequest_Chat": ".types", + "CreatePromptRequest_Text": ".types", + "CreateTextPromptRequest": ".types", + "PlaceholderMessage": ".types", + "Prompt": ".types", + "PromptMeta": ".types", + "PromptMetaListResponse": ".types", + "PromptType": ".types", + "Prompt_Chat": ".types", + "Prompt_Text": ".types", + "TextPrompt": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "BasePrompt", + "ChatMessage", + "ChatMessageWithPlaceholders", + "ChatMessageWithPlaceholders_Chatmessage", + "ChatMessageWithPlaceholders_Placeholder", + "ChatPrompt", + "CreateChatPromptRequest", + "CreatePromptRequest", + "CreatePromptRequest_Chat", + "CreatePromptRequest_Text", + "CreateTextPromptRequest", + "PlaceholderMessage", + "Prompt", + "PromptMeta", + "PromptMetaListResponse", + "PromptType", + "Prompt_Chat", + "Prompt_Text", + "TextPrompt", +] diff --git a/langfuse/api/prompts/client.py b/langfuse/api/prompts/client.py new file mode 100644 index 000000000..09f9b43ad --- /dev/null +++ b/langfuse/api/prompts/client.py @@ -0,0 +1,530 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawPromptsClient, RawPromptsClient +from .types.create_prompt_request import CreatePromptRequest +from .types.prompt import Prompt +from .types.prompt_meta_list_response import PromptMetaListResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class PromptsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawPromptsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawPromptsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawPromptsClient + """ + return self._raw_client + + def get( + self, + prompt_name: str, + *, + version: typing.Optional[int] = None, + label: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> Prompt: + """ + Get a prompt + + Parameters + ---------- + prompt_name : str + The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), + the folder path must be URL encoded. + + version : typing.Optional[int] + Version of the prompt to be retrieved. + + label : typing.Optional[str] + Label of the prompt to be retrieved. Defaults to "production" if no label or version is set. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Prompt + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.prompts.get( + prompt_name="promptName", + ) + """ + _response = self._raw_client.get( + prompt_name, version=version, label=label, request_options=request_options + ) + return _response.data + + def list( + self, + *, + name: typing.Optional[str] = None, + label: typing.Optional[str] = None, + tag: typing.Optional[str] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + from_updated_at: typing.Optional[dt.datetime] = None, + to_updated_at: typing.Optional[dt.datetime] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PromptMetaListResponse: + """ + Get a list of prompt names with versions and labels + + Parameters + ---------- + name : typing.Optional[str] + + label : typing.Optional[str] + + tag : typing.Optional[str] + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + from_updated_at : typing.Optional[dt.datetime] + Optional filter to only include prompt versions created/updated on or after a certain datetime (ISO 8601) + + to_updated_at : typing.Optional[dt.datetime] + Optional filter to only include prompt versions created/updated before a certain datetime (ISO 8601) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PromptMetaListResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.prompts.list() + """ + _response = self._raw_client.list( + name=name, + label=label, + tag=tag, + page=page, + limit=limit, + from_updated_at=from_updated_at, + to_updated_at=to_updated_at, + request_options=request_options, + ) + return _response.data + + def create( + self, + *, + request: CreatePromptRequest, + request_options: typing.Optional[RequestOptions] = None, + ) -> Prompt: + """ + Create a new version for the prompt with the given `name` + + Parameters + ---------- + request : CreatePromptRequest + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Prompt + + Examples + -------- + from langfuse import LangfuseAPI + from langfuse.prompts import ( + ChatMessageWithPlaceholders_Chatmessage, + CreatePromptRequest_Chat, + ) + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.prompts.create( + request=CreatePromptRequest_Chat( + name="name", + prompt=[ + ChatMessageWithPlaceholders_Chatmessage( + role="role", + content="content", + ), + ChatMessageWithPlaceholders_Chatmessage( + role="role", + content="content", + ), + ], + ), + ) + """ + _response = self._raw_client.create( + request=request, request_options=request_options + ) + return _response.data + + def delete( + self, + prompt_name: str, + *, + label: typing.Optional[str] = None, + version: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Delete prompt versions. If neither version nor label is specified, all versions of the prompt are deleted. + + Parameters + ---------- + prompt_name : str + The name of the prompt + + label : typing.Optional[str] + Optional label to filter deletion. If specified, deletes all prompt versions that have this label. + + version : typing.Optional[int] + Optional version to filter deletion. If specified, deletes only this specific version of the prompt. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.prompts.delete( + prompt_name="promptName", + ) + """ + _response = self._raw_client.delete( + prompt_name, label=label, version=version, request_options=request_options + ) + return _response.data + + +class AsyncPromptsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawPromptsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawPromptsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawPromptsClient + """ + return self._raw_client + + async def get( + self, + prompt_name: str, + *, + version: typing.Optional[int] = None, + label: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> Prompt: + """ + Get a prompt + + Parameters + ---------- + prompt_name : str + The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), + the folder path must be URL encoded. + + version : typing.Optional[int] + Version of the prompt to be retrieved. + + label : typing.Optional[str] + Label of the prompt to be retrieved. Defaults to "production" if no label or version is set. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Prompt + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.prompts.get( + prompt_name="promptName", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get( + prompt_name, version=version, label=label, request_options=request_options + ) + return _response.data + + async def list( + self, + *, + name: typing.Optional[str] = None, + label: typing.Optional[str] = None, + tag: typing.Optional[str] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + from_updated_at: typing.Optional[dt.datetime] = None, + to_updated_at: typing.Optional[dt.datetime] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PromptMetaListResponse: + """ + Get a list of prompt names with versions and labels + + Parameters + ---------- + name : typing.Optional[str] + + label : typing.Optional[str] + + tag : typing.Optional[str] + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + from_updated_at : typing.Optional[dt.datetime] + Optional filter to only include prompt versions created/updated on or after a certain datetime (ISO 8601) + + to_updated_at : typing.Optional[dt.datetime] + Optional filter to only include prompt versions created/updated before a certain datetime (ISO 8601) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PromptMetaListResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.prompts.list() + + + asyncio.run(main()) + """ + _response = await self._raw_client.list( + name=name, + label=label, + tag=tag, + page=page, + limit=limit, + from_updated_at=from_updated_at, + to_updated_at=to_updated_at, + request_options=request_options, + ) + return _response.data + + async def create( + self, + *, + request: CreatePromptRequest, + request_options: typing.Optional[RequestOptions] = None, + ) -> Prompt: + """ + Create a new version for the prompt with the given `name` + + Parameters + ---------- + request : CreatePromptRequest + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Prompt + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + from langfuse.prompts import ( + ChatMessageWithPlaceholders_Chatmessage, + CreatePromptRequest_Chat, + ) + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.prompts.create( + request=CreatePromptRequest_Chat( + name="name", + prompt=[ + ChatMessageWithPlaceholders_Chatmessage( + role="role", + content="content", + ), + ChatMessageWithPlaceholders_Chatmessage( + role="role", + content="content", + ), + ], + ), + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create( + request=request, request_options=request_options + ) + return _response.data + + async def delete( + self, + prompt_name: str, + *, + label: typing.Optional[str] = None, + version: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> None: + """ + Delete prompt versions. If neither version nor label is specified, all versions of the prompt are deleted. + + Parameters + ---------- + prompt_name : str + The name of the prompt + + label : typing.Optional[str] + Optional label to filter deletion. If specified, deletes all prompt versions that have this label. + + version : typing.Optional[int] + Optional version to filter deletion. If specified, deletes only this specific version of the prompt. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.prompts.delete( + prompt_name="promptName", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete( + prompt_name, label=label, version=version, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/prompts/raw_client.py b/langfuse/api/prompts/raw_client.py new file mode 100644 index 000000000..81b108968 --- /dev/null +++ b/langfuse/api/prompts/raw_client.py @@ -0,0 +1,977 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.datetime_utils import serialize_datetime +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from ..core.serialization import convert_and_respect_annotation_metadata +from .types.create_prompt_request import CreatePromptRequest +from .types.prompt import Prompt +from .types.prompt_meta_list_response import PromptMetaListResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawPromptsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get( + self, + prompt_name: str, + *, + version: typing.Optional[int] = None, + label: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Prompt]: + """ + Get a prompt + + Parameters + ---------- + prompt_name : str + The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), + the folder path must be URL encoded. + + version : typing.Optional[int] + Version of the prompt to be retrieved. + + label : typing.Optional[str] + Label of the prompt to be retrieved. Defaults to "production" if no label or version is set. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Prompt] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/v2/prompts/{jsonable_encoder(prompt_name)}", + method="GET", + params={ + "version": version, + "label": label, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Prompt, + parse_obj_as( + type_=Prompt, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def list( + self, + *, + name: typing.Optional[str] = None, + label: typing.Optional[str] = None, + tag: typing.Optional[str] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + from_updated_at: typing.Optional[dt.datetime] = None, + to_updated_at: typing.Optional[dt.datetime] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[PromptMetaListResponse]: + """ + Get a list of prompt names with versions and labels + + Parameters + ---------- + name : typing.Optional[str] + + label : typing.Optional[str] + + tag : typing.Optional[str] + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + from_updated_at : typing.Optional[dt.datetime] + Optional filter to only include prompt versions created/updated on or after a certain datetime (ISO 8601) + + to_updated_at : typing.Optional[dt.datetime] + Optional filter to only include prompt versions created/updated before a certain datetime (ISO 8601) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[PromptMetaListResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/v2/prompts", + method="GET", + params={ + "name": name, + "label": label, + "tag": tag, + "page": page, + "limit": limit, + "fromUpdatedAt": serialize_datetime(from_updated_at) + if from_updated_at is not None + else None, + "toUpdatedAt": serialize_datetime(to_updated_at) + if to_updated_at is not None + else None, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PromptMetaListResponse, + parse_obj_as( + type_=PromptMetaListResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def create( + self, + *, + request: CreatePromptRequest, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Prompt]: + """ + Create a new version for the prompt with the given `name` + + Parameters + ---------- + request : CreatePromptRequest + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Prompt] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/v2/prompts", + method="POST", + json=convert_and_respect_annotation_metadata( + object_=request, annotation=CreatePromptRequest, direction="write" + ), + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Prompt, + parse_obj_as( + type_=Prompt, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete( + self, + prompt_name: str, + *, + label: typing.Optional[str] = None, + version: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[None]: + """ + Delete prompt versions. If neither version nor label is specified, all versions of the prompt are deleted. + + Parameters + ---------- + prompt_name : str + The name of the prompt + + label : typing.Optional[str] + Optional label to filter deletion. If specified, deletes all prompt versions that have this label. + + version : typing.Optional[int] + Optional version to filter deletion. If specified, deletes only this specific version of the prompt. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[None] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/v2/prompts/{jsonable_encoder(prompt_name)}", + method="DELETE", + params={ + "label": label, + "version": version, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return HttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawPromptsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get( + self, + prompt_name: str, + *, + version: typing.Optional[int] = None, + label: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Prompt]: + """ + Get a prompt + + Parameters + ---------- + prompt_name : str + The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), + the folder path must be URL encoded. + + version : typing.Optional[int] + Version of the prompt to be retrieved. + + label : typing.Optional[str] + Label of the prompt to be retrieved. Defaults to "production" if no label or version is set. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Prompt] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/v2/prompts/{jsonable_encoder(prompt_name)}", + method="GET", + params={ + "version": version, + "label": label, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Prompt, + parse_obj_as( + type_=Prompt, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def list( + self, + *, + name: typing.Optional[str] = None, + label: typing.Optional[str] = None, + tag: typing.Optional[str] = None, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + from_updated_at: typing.Optional[dt.datetime] = None, + to_updated_at: typing.Optional[dt.datetime] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[PromptMetaListResponse]: + """ + Get a list of prompt names with versions and labels + + Parameters + ---------- + name : typing.Optional[str] + + label : typing.Optional[str] + + tag : typing.Optional[str] + + page : typing.Optional[int] + page number, starts at 1 + + limit : typing.Optional[int] + limit of items per page + + from_updated_at : typing.Optional[dt.datetime] + Optional filter to only include prompt versions created/updated on or after a certain datetime (ISO 8601) + + to_updated_at : typing.Optional[dt.datetime] + Optional filter to only include prompt versions created/updated before a certain datetime (ISO 8601) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[PromptMetaListResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/v2/prompts", + method="GET", + params={ + "name": name, + "label": label, + "tag": tag, + "page": page, + "limit": limit, + "fromUpdatedAt": serialize_datetime(from_updated_at) + if from_updated_at is not None + else None, + "toUpdatedAt": serialize_datetime(to_updated_at) + if to_updated_at is not None + else None, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PromptMetaListResponse, + parse_obj_as( + type_=PromptMetaListResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def create( + self, + *, + request: CreatePromptRequest, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Prompt]: + """ + Create a new version for the prompt with the given `name` + + Parameters + ---------- + request : CreatePromptRequest + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Prompt] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/v2/prompts", + method="POST", + json=convert_and_respect_annotation_metadata( + object_=request, annotation=CreatePromptRequest, direction="write" + ), + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Prompt, + parse_obj_as( + type_=Prompt, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete( + self, + prompt_name: str, + *, + label: typing.Optional[str] = None, + version: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[None]: + """ + Delete prompt versions. If neither version nor label is specified, all versions of the prompt are deleted. + + Parameters + ---------- + prompt_name : str + The name of the prompt + + label : typing.Optional[str] + Optional label to filter deletion. If specified, deletes all prompt versions that have this label. + + version : typing.Optional[int] + Optional version to filter deletion. If specified, deletes only this specific version of the prompt. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[None] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/v2/prompts/{jsonable_encoder(prompt_name)}", + method="DELETE", + params={ + "label": label, + "version": version, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/prompts/types/__init__.py b/langfuse/api/prompts/types/__init__.py new file mode 100644 index 000000000..fbe81d8cd --- /dev/null +++ b/langfuse/api/prompts/types/__init__.py @@ -0,0 +1,100 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .base_prompt import BasePrompt + from .chat_message import ChatMessage + from .chat_message_with_placeholders import ( + ChatMessageWithPlaceholders, + ChatMessageWithPlaceholders_Chatmessage, + ChatMessageWithPlaceholders_Placeholder, + ) + from .chat_prompt import ChatPrompt + from .create_chat_prompt_request import CreateChatPromptRequest + from .create_prompt_request import ( + CreatePromptRequest, + CreatePromptRequest_Chat, + CreatePromptRequest_Text, + ) + from .create_text_prompt_request import CreateTextPromptRequest + from .placeholder_message import PlaceholderMessage + from .prompt import Prompt, Prompt_Chat, Prompt_Text + from .prompt_meta import PromptMeta + from .prompt_meta_list_response import PromptMetaListResponse + from .prompt_type import PromptType + from .text_prompt import TextPrompt +_dynamic_imports: typing.Dict[str, str] = { + "BasePrompt": ".base_prompt", + "ChatMessage": ".chat_message", + "ChatMessageWithPlaceholders": ".chat_message_with_placeholders", + "ChatMessageWithPlaceholders_Chatmessage": ".chat_message_with_placeholders", + "ChatMessageWithPlaceholders_Placeholder": ".chat_message_with_placeholders", + "ChatPrompt": ".chat_prompt", + "CreateChatPromptRequest": ".create_chat_prompt_request", + "CreatePromptRequest": ".create_prompt_request", + "CreatePromptRequest_Chat": ".create_prompt_request", + "CreatePromptRequest_Text": ".create_prompt_request", + "CreateTextPromptRequest": ".create_text_prompt_request", + "PlaceholderMessage": ".placeholder_message", + "Prompt": ".prompt", + "PromptMeta": ".prompt_meta", + "PromptMetaListResponse": ".prompt_meta_list_response", + "PromptType": ".prompt_type", + "Prompt_Chat": ".prompt", + "Prompt_Text": ".prompt", + "TextPrompt": ".text_prompt", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "BasePrompt", + "ChatMessage", + "ChatMessageWithPlaceholders", + "ChatMessageWithPlaceholders_Chatmessage", + "ChatMessageWithPlaceholders_Placeholder", + "ChatPrompt", + "CreateChatPromptRequest", + "CreatePromptRequest", + "CreatePromptRequest_Chat", + "CreatePromptRequest_Text", + "CreateTextPromptRequest", + "PlaceholderMessage", + "Prompt", + "PromptMeta", + "PromptMetaListResponse", + "PromptType", + "Prompt_Chat", + "Prompt_Text", + "TextPrompt", +] diff --git a/langfuse/api/prompts/types/base_prompt.py b/langfuse/api/prompts/types/base_prompt.py new file mode 100644 index 000000000..2924490f2 --- /dev/null +++ b/langfuse/api/prompts/types/base_prompt.py @@ -0,0 +1,49 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class BasePrompt(UniversalBaseModel): + name: str + version: int + config: typing.Any + labels: typing.List[str] = pydantic.Field() + """ + List of deployment labels of this prompt version. + """ + + tags: typing.List[str] = pydantic.Field() + """ + List of tags. Used to filter via UI and API. The same across versions of a prompt. + """ + + commit_message: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="commitMessage") + ] = pydantic.Field(default=None) + """ + Commit message for this prompt version. + """ + + resolution_graph: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, typing.Any]], + FieldMetadata(alias="resolutionGraph"), + ] = pydantic.Field(default=None) + """ + The dependency resolution graph for the current prompt. Null if prompt has no dependencies. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/prompts/types/chat_message.py b/langfuse/api/prompts/types/chat_message.py new file mode 100644 index 000000000..045bf067e --- /dev/null +++ b/langfuse/api/prompts/types/chat_message.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ChatMessage(UniversalBaseModel): + role: str + content: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/prompts/types/chat_message_with_placeholders.py b/langfuse/api/prompts/types/chat_message_with_placeholders.py new file mode 100644 index 000000000..7e05fd76f --- /dev/null +++ b/langfuse/api/prompts/types/chat_message_with_placeholders.py @@ -0,0 +1,50 @@ +# This file was auto-generated by Fern from our API Definition. + +from __future__ import annotations + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ChatMessageWithPlaceholders_Chatmessage(UniversalBaseModel): + type: typing.Literal["chatmessage"] = "chatmessage" + role: str + content: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class ChatMessageWithPlaceholders_Placeholder(UniversalBaseModel): + type: typing.Literal["placeholder"] = "placeholder" + name: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +ChatMessageWithPlaceholders = typing_extensions.Annotated[ + typing.Union[ + ChatMessageWithPlaceholders_Chatmessage, ChatMessageWithPlaceholders_Placeholder + ], + pydantic.Field(discriminator="type"), +] diff --git a/langfuse/api/prompts/types/chat_prompt.py b/langfuse/api/prompts/types/chat_prompt.py new file mode 100644 index 000000000..5e40152e9 --- /dev/null +++ b/langfuse/api/prompts/types/chat_prompt.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_prompt import BasePrompt +from .chat_message_with_placeholders import ChatMessageWithPlaceholders + + +class ChatPrompt(BasePrompt): + prompt: typing.List[ChatMessageWithPlaceholders] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/prompts/types/create_chat_prompt_request.py b/langfuse/api/prompts/types/create_chat_prompt_request.py new file mode 100644 index 000000000..8ddc2a946 --- /dev/null +++ b/langfuse/api/prompts/types/create_chat_prompt_request.py @@ -0,0 +1,42 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .chat_message_with_placeholders import ChatMessageWithPlaceholders + + +class CreateChatPromptRequest(UniversalBaseModel): + name: str + prompt: typing.List[ChatMessageWithPlaceholders] + config: typing.Optional[typing.Any] = None + labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of deployment labels of this prompt version. + """ + + tags: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of tags to apply to all versions of this prompt. + """ + + commit_message: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="commitMessage") + ] = pydantic.Field(default=None) + """ + Commit message for this prompt version. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/prompts/types/create_prompt_request.py b/langfuse/api/prompts/types/create_prompt_request.py new file mode 100644 index 000000000..8c144871e --- /dev/null +++ b/langfuse/api/prompts/types/create_prompt_request.py @@ -0,0 +1,63 @@ +# This file was auto-generated by Fern from our API Definition. + +from __future__ import annotations + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .chat_message_with_placeholders import ChatMessageWithPlaceholders + + +class CreatePromptRequest_Chat(UniversalBaseModel): + type: typing.Literal["chat"] = "chat" + name: str + prompt: typing.List[ChatMessageWithPlaceholders] + config: typing.Optional[typing.Any] = None + labels: typing.Optional[typing.List[str]] = None + tags: typing.Optional[typing.List[str]] = None + commit_message: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="commitMessage") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class CreatePromptRequest_Text(UniversalBaseModel): + type: typing.Literal["text"] = "text" + name: str + prompt: str + config: typing.Optional[typing.Any] = None + labels: typing.Optional[typing.List[str]] = None + tags: typing.Optional[typing.List[str]] = None + commit_message: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="commitMessage") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +CreatePromptRequest = typing_extensions.Annotated[ + typing.Union[CreatePromptRequest_Chat, CreatePromptRequest_Text], + pydantic.Field(discriminator="type"), +] diff --git a/langfuse/api/prompts/types/create_text_prompt_request.py b/langfuse/api/prompts/types/create_text_prompt_request.py new file mode 100644 index 000000000..12b50cbc7 --- /dev/null +++ b/langfuse/api/prompts/types/create_text_prompt_request.py @@ -0,0 +1,41 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class CreateTextPromptRequest(UniversalBaseModel): + name: str + prompt: str + config: typing.Optional[typing.Any] = None + labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of deployment labels of this prompt version. + """ + + tags: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + List of tags to apply to all versions of this prompt. + """ + + commit_message: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="commitMessage") + ] = pydantic.Field(default=None) + """ + Commit message for this prompt version. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/prompts/types/placeholder_message.py b/langfuse/api/prompts/types/placeholder_message.py new file mode 100644 index 000000000..9764675d0 --- /dev/null +++ b/langfuse/api/prompts/types/placeholder_message.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class PlaceholderMessage(UniversalBaseModel): + name: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/prompts/types/prompt.py b/langfuse/api/prompts/types/prompt.py new file mode 100644 index 000000000..aeea93d3a --- /dev/null +++ b/langfuse/api/prompts/types/prompt.py @@ -0,0 +1,72 @@ +# This file was auto-generated by Fern from our API Definition. + +from __future__ import annotations + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .chat_message_with_placeholders import ChatMessageWithPlaceholders + + +class Prompt_Chat(UniversalBaseModel): + type: typing.Literal["chat"] = "chat" + prompt: typing.List[ChatMessageWithPlaceholders] + name: str + version: int + config: typing.Any + labels: typing.List[str] + tags: typing.List[str] + commit_message: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="commitMessage") + ] = None + resolution_graph: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, typing.Any]], + FieldMetadata(alias="resolutionGraph"), + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class Prompt_Text(UniversalBaseModel): + type: typing.Literal["text"] = "text" + prompt: str + name: str + version: int + config: typing.Any + labels: typing.List[str] + tags: typing.List[str] + commit_message: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="commitMessage") + ] = None + resolution_graph: typing_extensions.Annotated[ + typing.Optional[typing.Dict[str, typing.Any]], + FieldMetadata(alias="resolutionGraph"), + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +Prompt = typing_extensions.Annotated[ + typing.Union[Prompt_Chat, Prompt_Text], pydantic.Field(discriminator="type") +] diff --git a/langfuse/api/prompts/types/prompt_meta.py b/langfuse/api/prompts/types/prompt_meta.py new file mode 100644 index 000000000..75929d448 --- /dev/null +++ b/langfuse/api/prompts/types/prompt_meta.py @@ -0,0 +1,42 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .prompt_type import PromptType + + +class PromptMeta(UniversalBaseModel): + name: str + type: PromptType = pydantic.Field() + """ + Indicates whether the prompt is a text or chat prompt. + """ + + versions: typing.List[int] + labels: typing.List[str] + tags: typing.List[str] + last_updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="lastUpdatedAt") + ] + last_config: typing_extensions.Annotated[ + typing.Any, FieldMetadata(alias="lastConfig") + ] = pydantic.Field() + """ + Config object of the most recent prompt version that matches the filters (if any are provided) + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/prompts/types/prompt_meta_list_response.py b/langfuse/api/prompts/types/prompt_meta_list_response.py new file mode 100644 index 000000000..725a86442 --- /dev/null +++ b/langfuse/api/prompts/types/prompt_meta_list_response.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse +from .prompt_meta import PromptMeta + + +class PromptMetaListResponse(UniversalBaseModel): + data: typing.List[PromptMeta] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/prompts/types/prompt_type.py b/langfuse/api/prompts/types/prompt_type.py new file mode 100644 index 000000000..a6676ae50 --- /dev/null +++ b/langfuse/api/prompts/types/prompt_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +PromptType = typing.Union[typing.Literal["chat", "text"], typing.Any] diff --git a/langfuse/api/prompts/types/text_prompt.py b/langfuse/api/prompts/types/text_prompt.py new file mode 100644 index 000000000..046e904ae --- /dev/null +++ b/langfuse/api/prompts/types/text_prompt.py @@ -0,0 +1,22 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .base_prompt import BasePrompt + + +class TextPrompt(BasePrompt): + prompt: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/reference.md b/langfuse/api/reference.md deleted file mode 100644 index 66c008bb7..000000000 --- a/langfuse/api/reference.md +++ /dev/null @@ -1,7553 +0,0 @@ -# Reference -## AnnotationQueues -
client.annotation_queues.list_queues(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get all annotation queues -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.annotation_queues.list_queues() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**page:** `typing.Optional[int]` — page number, starts at 1 - -
-
- -
-
- -**limit:** `typing.Optional[int]` — limit of items per page - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.annotation_queues.create_queue(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create an annotation queue -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import CreateAnnotationQueueRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.annotation_queues.create_queue( - request=CreateAnnotationQueueRequest( - name="name", - score_config_ids=["scoreConfigIds", "scoreConfigIds"], - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `CreateAnnotationQueueRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.annotation_queues.get_queue(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get an annotation queue by ID -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.annotation_queues.get_queue( - queue_id="queueId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**queue_id:** `str` — The unique identifier of the annotation queue - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.annotation_queues.list_queue_items(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get items for a specific annotation queue -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.annotation_queues.list_queue_items( - queue_id="queueId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**queue_id:** `str` — The unique identifier of the annotation queue - -
-
- -
-
- -**status:** `typing.Optional[AnnotationQueueStatus]` — Filter by status - -
-
- -
-
- -**page:** `typing.Optional[int]` — page number, starts at 1 - -
-
- -
-
- -**limit:** `typing.Optional[int]` — limit of items per page - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.annotation_queues.get_queue_item(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a specific item from an annotation queue -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.annotation_queues.get_queue_item( - queue_id="queueId", - item_id="itemId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**queue_id:** `str` — The unique identifier of the annotation queue - -
-
- -
-
- -**item_id:** `str` — The unique identifier of the annotation queue item - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.annotation_queues.create_queue_item(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Add an item to an annotation queue -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import AnnotationQueueObjectType, CreateAnnotationQueueItemRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.annotation_queues.create_queue_item( - queue_id="queueId", - request=CreateAnnotationQueueItemRequest( - object_id="objectId", - object_type=AnnotationQueueObjectType.TRACE, - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**queue_id:** `str` — The unique identifier of the annotation queue - -
-
- -
-
- -**request:** `CreateAnnotationQueueItemRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.annotation_queues.update_queue_item(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update an annotation queue item -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import UpdateAnnotationQueueItemRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.annotation_queues.update_queue_item( - queue_id="queueId", - item_id="itemId", - request=UpdateAnnotationQueueItemRequest(), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**queue_id:** `str` — The unique identifier of the annotation queue - -
-
- -
-
- -**item_id:** `str` — The unique identifier of the annotation queue item - -
-
- -
-
- -**request:** `UpdateAnnotationQueueItemRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.annotation_queues.delete_queue_item(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Remove an item from an annotation queue -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.annotation_queues.delete_queue_item( - queue_id="queueId", - item_id="itemId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**queue_id:** `str` — The unique identifier of the annotation queue - -
-
- -
-
- -**item_id:** `str` — The unique identifier of the annotation queue item - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.annotation_queues.create_queue_assignment(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create an assignment for a user to an annotation queue -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import AnnotationQueueAssignmentRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.annotation_queues.create_queue_assignment( - queue_id="queueId", - request=AnnotationQueueAssignmentRequest( - user_id="userId", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**queue_id:** `str` — The unique identifier of the annotation queue - -
-
- -
-
- -**request:** `AnnotationQueueAssignmentRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.annotation_queues.delete_queue_assignment(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete an assignment for a user to an annotation queue -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import AnnotationQueueAssignmentRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.annotation_queues.delete_queue_assignment( - queue_id="queueId", - request=AnnotationQueueAssignmentRequest( - user_id="userId", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**queue_id:** `str` — The unique identifier of the annotation queue - -
-
- -
-
- -**request:** `AnnotationQueueAssignmentRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## BlobStorageIntegrations -
client.blob_storage_integrations.get_blob_storage_integrations() -
-
- -#### 📝 Description - -
-
- -
-
- -Get all blob storage integrations for the organization (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.blob_storage_integrations.get_blob_storage_integrations() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.blob_storage_integrations.upsert_blob_storage_integration(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create or update a blob storage integration for a specific project (requires organization-scoped API key). The configuration is validated by performing a test upload to the bucket. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import ( - BlobStorageExportFrequency, - BlobStorageExportMode, - BlobStorageIntegrationFileType, - BlobStorageIntegrationType, - CreateBlobStorageIntegrationRequest, -) -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.blob_storage_integrations.upsert_blob_storage_integration( - request=CreateBlobStorageIntegrationRequest( - project_id="projectId", - type=BlobStorageIntegrationType.S_3, - bucket_name="bucketName", - region="region", - export_frequency=BlobStorageExportFrequency.HOURLY, - enabled=True, - force_path_style=True, - file_type=BlobStorageIntegrationFileType.JSON, - export_mode=BlobStorageExportMode.FULL_HISTORY, - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `CreateBlobStorageIntegrationRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.blob_storage_integrations.delete_blob_storage_integration(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a blob storage integration by ID (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.blob_storage_integrations.delete_blob_storage_integration( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Comments -
client.comments.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a comment. Comments may be attached to different object types (trace, observation, session, prompt). -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import CreateCommentRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.comments.create( - request=CreateCommentRequest( - project_id="projectId", - object_type="objectType", - object_id="objectId", - content="content", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `CreateCommentRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.comments.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get all comments -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.comments.get() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**page:** `typing.Optional[int]` — Page number, starts at 1. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit - -
-
- -
-
- -**object_type:** `typing.Optional[str]` — Filter comments by object type (trace, observation, session, prompt). - -
-
- -
-
- -**object_id:** `typing.Optional[str]` — Filter comments by object id. If objectType is not provided, an error will be thrown. - -
-
- -
-
- -**author_user_id:** `typing.Optional[str]` — Filter comments by author user id. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.comments.get_by_id(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a comment by id -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.comments.get_by_id( - comment_id="commentId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**comment_id:** `str` — The unique langfuse identifier of a comment - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## DatasetItems -
client.dataset_items.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a dataset item -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import CreateDatasetItemRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.dataset_items.create( - request=CreateDatasetItemRequest( - dataset_name="datasetName", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `CreateDatasetItemRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.dataset_items.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a dataset item -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.dataset_items.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.dataset_items.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get dataset items -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.dataset_items.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**dataset_name:** `typing.Optional[str]` - -
-
- -
-
- -**source_trace_id:** `typing.Optional[str]` - -
-
- -
-
- -**source_observation_id:** `typing.Optional[str]` - -
-
- -
-
- -**page:** `typing.Optional[int]` — page number, starts at 1 - -
-
- -
-
- -**limit:** `typing.Optional[int]` — limit of items per page - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.dataset_items.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a dataset item and all its run items. This action is irreversible. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.dataset_items.delete( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## DatasetRunItems -
client.dataset_run_items.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a dataset run item -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import CreateDatasetRunItemRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.dataset_run_items.create( - request=CreateDatasetRunItemRequest( - run_name="runName", - dataset_item_id="datasetItemId", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `CreateDatasetRunItemRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.dataset_run_items.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List dataset run items -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.dataset_run_items.list( - dataset_id="datasetId", - run_name="runName", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**dataset_id:** `str` - -
-
- -
-
- -**run_name:** `str` - -
-
- -
-
- -**page:** `typing.Optional[int]` — page number, starts at 1 - -
-
- -
-
- -**limit:** `typing.Optional[int]` — limit of items per page - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Datasets -
client.datasets.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get all datasets -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.datasets.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**page:** `typing.Optional[int]` — page number, starts at 1 - -
-
- -
-
- -**limit:** `typing.Optional[int]` — limit of items per page - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.datasets.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a dataset -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.datasets.get( - dataset_name="datasetName", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**dataset_name:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.datasets.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a dataset -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import CreateDatasetRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.datasets.create( - request=CreateDatasetRequest( - name="name", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `CreateDatasetRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.datasets.get_run(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a dataset run and its items -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.datasets.get_run( - dataset_name="datasetName", - run_name="runName", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**dataset_name:** `str` - -
-
- -
-
- -**run_name:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.datasets.delete_run(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a dataset run and all its run items. This action is irreversible. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.datasets.delete_run( - dataset_name="datasetName", - run_name="runName", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**dataset_name:** `str` - -
-
- -
-
- -**run_name:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.datasets.get_runs(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get dataset runs -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.datasets.get_runs( - dataset_name="datasetName", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**dataset_name:** `str` - -
-
- -
-
- -**page:** `typing.Optional[int]` — page number, starts at 1 - -
-
- -
-
- -**limit:** `typing.Optional[int]` — limit of items per page - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Health -
client.health.health() -
-
- -#### 📝 Description - -
-
- -
-
- -Check health of API and database -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.health.health() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Ingestion -
client.ingestion.batch(...) -
-
- -#### 📝 Description - -
-
- -
-
- -**Legacy endpoint for batch ingestion for Langfuse Observability.** - --> Please use the OpenTelemetry endpoint (`/api/public/otel/v1/traces`). Learn more: https://langfuse.com/integrations/native/opentelemetry - -Within each batch, there can be multiple events. -Each event has a type, an id, a timestamp, metadata and a body. -Internally, we refer to this as the "event envelope" as it tells us something about the event but not the trace. -We use the event id within this envelope to deduplicate messages to avoid processing the same event twice, i.e. the event id should be unique per request. -The event.body.id is the ID of the actual trace and will be used for updates and will be visible within the Langfuse App. -I.e. if you want to update a trace, you'd use the same body id, but separate event IDs. - -Notes: -- Introduction to data model: https://langfuse.com/docs/observability/data-model -- Batch sizes are limited to 3.5 MB in total. You need to adjust the number of events per batch accordingly. -- The API does not return a 4xx status code for input errors. Instead, it responds with a 207 status code, which includes a list of the encountered errors. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import IngestionEvent_ScoreCreate, ScoreBody -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.ingestion.batch( - batch=[ - IngestionEvent_ScoreCreate( - id="abcdef-1234-5678-90ab", - timestamp="2022-01-01T00:00:00.000Z", - body=ScoreBody( - id="abcdef-1234-5678-90ab", - trace_id="1234-5678-90ab-cdef", - name="My Score", - value=0.9, - environment="default", - ), - ) - ], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**batch:** `typing.Sequence[IngestionEvent]` — Batch of tracing events to be ingested. Discriminated by attribute `type`. - -
-
- -
-
- -**metadata:** `typing.Optional[typing.Any]` — Optional. Metadata field used by the Langfuse SDKs for debugging. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## LlmConnections -
client.llm_connections.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get all LLM connections in a project -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.llm_connections.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**page:** `typing.Optional[int]` — page number, starts at 1 - -
-
- -
-
- -**limit:** `typing.Optional[int]` — limit of items per page - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.llm_connections.upsert(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create or update an LLM connection. The connection is upserted on provider. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import LlmAdapter, UpsertLlmConnectionRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.llm_connections.upsert( - request=UpsertLlmConnectionRequest( - provider="provider", - adapter=LlmAdapter.ANTHROPIC, - secret_key="secretKey", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `UpsertLlmConnectionRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Media -
client.media.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a media record -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.media.get( - media_id="mediaId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**media_id:** `str` — The unique langfuse identifier of a media record - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.media.patch(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Patch a media record -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -import datetime - -from langfuse import PatchMediaBody -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.media.patch( - media_id="mediaId", - request=PatchMediaBody( - uploaded_at=datetime.datetime.fromisoformat( - "2024-01-15 09:30:00+00:00", - ), - upload_http_status=1, - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**media_id:** `str` — The unique langfuse identifier of a media record - -
-
- -
-
- -**request:** `PatchMediaBody` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.media.get_upload_url(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a presigned upload URL for a media record -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import GetMediaUploadUrlRequest, MediaContentType -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.media.get_upload_url( - request=GetMediaUploadUrlRequest( - trace_id="traceId", - content_type=MediaContentType.IMAGE_PNG, - content_length=1, - sha_256_hash="sha256Hash", - field="field", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `GetMediaUploadUrlRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Metrics -
client.metrics.metrics(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get metrics from the Langfuse project using a query object. - -For more details, see the [Metrics API documentation](https://langfuse.com/docs/metrics/features/metrics-api). -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.metrics.metrics( - query="query", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**query:** `str` - -JSON string containing the query parameters with the following structure: -```json -{ - "view": string, // Required. One of "traces", "observations", "scores-numeric", "scores-categorical" - "dimensions": [ // Optional. Default: [] - { - "field": string // Field to group by, e.g. "name", "userId", "sessionId" - } - ], - "metrics": [ // Required. At least one metric must be provided - { - "measure": string, // What to measure, e.g. "count", "latency", "value" - "aggregation": string // How to aggregate, e.g. "count", "sum", "avg", "p95", "histogram" - } - ], - "filters": [ // Optional. Default: [] - { - "column": string, // Column to filter on - "operator": string, // Operator, e.g. "=", ">", "<", "contains" - "value": any, // Value to compare against - "type": string, // Data type, e.g. "string", "number", "stringObject" - "key": string // Required only when filtering on metadata - } - ], - "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time - "granularity": string // One of "minute", "hour", "day", "week", "month", "auto" - }, - "fromTimestamp": string, // Required. ISO datetime string for start of time range - "toTimestamp": string, // Required. ISO datetime string for end of time range - "orderBy": [ // Optional. Default: null - { - "field": string, // Field to order by - "direction": string // "asc" or "desc" - } - ], - "config": { // Optional. Query-specific configuration - "bins": number, // Optional. Number of bins for histogram (1-100), default: 10 - "row_limit": number // Optional. Row limit for results (1-1000) - } -} -``` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Models -
client.models.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a model -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import CreateModelRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.models.create( - request=CreateModelRequest( - model_name="modelName", - match_pattern="matchPattern", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `CreateModelRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.models.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get all models -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.models.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**page:** `typing.Optional[int]` — page number, starts at 1 - -
-
- -
-
- -**limit:** `typing.Optional[int]` — limit of items per page - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.models.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a model -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.models.get( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.models.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a model. Cannot delete models managed by Langfuse. You can create your own definition with the same modelName to override the definition though. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.models.delete( - id="id", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Observations -
client.observations.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a observation -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.observations.get( - observation_id="observationId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**observation_id:** `str` — The unique langfuse identifier of an observation, can be an event, span or generation - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.observations.get_many(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a list of observations -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.observations.get_many() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**page:** `typing.Optional[int]` — Page number, starts at 1. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**user_id:** `typing.Optional[str]` - -
-
- -
-
- -**type:** `typing.Optional[str]` - -
-
- -
-
- -**trace_id:** `typing.Optional[str]` - -
-
- -
-
- -**level:** `typing.Optional[ObservationLevel]` — Optional filter for observations with a specific level (e.g. "DEBUG", "DEFAULT", "WARNING", "ERROR"). - -
-
- -
-
- -**parent_observation_id:** `typing.Optional[str]` - -
-
- -
-
- -**environment:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Optional filter for observations where the environment is one of the provided values. - -
-
- -
-
- -**from_start_time:** `typing.Optional[dt.datetime]` — Retrieve only observations with a start_time on or after this datetime (ISO 8601). - -
-
- -
-
- -**to_start_time:** `typing.Optional[dt.datetime]` — Retrieve only observations with a start_time before this datetime (ISO 8601). - -
-
- -
-
- -**version:** `typing.Optional[str]` — Optional filter to only include observations with a certain version. - -
-
- -
-
- -**filter:** `typing.Optional[str]` - -JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, type, level, environment, fromStartTime, ...). - -## Filter Structure -Each filter condition has the following structure: -```json -[ - { - "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" - "column": string, // Required. Column to filter on (see available columns below) - "operator": string, // Required. Operator based on type: - // - datetime: ">", "<", ">=", "<=" - // - string: "=", "contains", "does not contain", "starts with", "ends with" - // - stringOptions: "any of", "none of" - // - categoryOptions: "any of", "none of" - // - arrayOptions: "any of", "none of", "all of" - // - number: "=", ">", "<", ">=", "<=" - // - stringObject: "=", "contains", "does not contain", "starts with", "ends with" - // - numberObject: "=", ">", "<", ">=", "<=" - // - boolean: "=", "<>" - // - null: "is null", "is not null" - "value": any, // Required (except for null type). Value to compare against. Type depends on filter type - "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata - } -] -``` - -## Available Columns - -### Core Observation Fields -- `id` (string) - Observation ID -- `type` (string) - Observation type (SPAN, GENERATION, EVENT) -- `name` (string) - Observation name -- `traceId` (string) - Associated trace ID -- `startTime` (datetime) - Observation start time -- `endTime` (datetime) - Observation end time -- `environment` (string) - Environment tag -- `level` (string) - Log level (DEBUG, DEFAULT, WARNING, ERROR) -- `statusMessage` (string) - Status message -- `version` (string) - Version tag - -### Performance Metrics -- `latency` (number) - Latency in seconds (calculated: end_time - start_time) -- `timeToFirstToken` (number) - Time to first token in seconds -- `tokensPerSecond` (number) - Output tokens per second - -### Token Usage -- `inputTokens` (number) - Number of input tokens -- `outputTokens` (number) - Number of output tokens -- `totalTokens` (number) - Total tokens (alias: `tokens`) - -### Cost Metrics -- `inputCost` (number) - Input cost in USD -- `outputCost` (number) - Output cost in USD -- `totalCost` (number) - Total cost in USD - -### Model Information -- `model` (string) - Provided model name -- `promptName` (string) - Associated prompt name -- `promptVersion` (number) - Associated prompt version - -### Structured Data -- `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys. - -### Associated Trace Fields (requires join with traces table) -- `userId` (string) - User ID from associated trace -- `traceName` (string) - Name from associated trace -- `traceEnvironment` (string) - Environment from associated trace -- `traceTags` (arrayOptions) - Tags from associated trace - -## Filter Examples -```json -[ - { - "type": "string", - "column": "type", - "operator": "=", - "value": "GENERATION" - }, - { - "type": "number", - "column": "latency", - "operator": ">=", - "value": 2.5 - }, - { - "type": "stringObject", - "column": "metadata", - "key": "environment", - "operator": "=", - "value": "production" - } -] -``` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Opentelemetry -
client.opentelemetry.export_traces(...) -
-
- -#### 📝 Description - -
-
- -
-
- -**OpenTelemetry Traces Ingestion Endpoint** - -This endpoint implements the OTLP/HTTP specification for trace ingestion, providing native OpenTelemetry integration for Langfuse Observability. - -**Supported Formats:** -- Binary Protobuf: `Content-Type: application/x-protobuf` -- JSON Protobuf: `Content-Type: application/json` -- Supports gzip compression via `Content-Encoding: gzip` header - -**Specification Compliance:** -- Conforms to [OTLP/HTTP Trace Export](https://opentelemetry.io/docs/specs/otlp/#otlphttp) -- Implements `ExportTraceServiceRequest` message format - -**Documentation:** -- Integration guide: https://langfuse.com/integrations/native/opentelemetry -- Data model: https://langfuse.com/docs/observability/data-model -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import ( - OtelAttribute, - OtelAttributeValue, - OtelResource, - OtelResourceSpan, - OtelScope, - OtelScopeSpan, - OtelSpan, -) -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.opentelemetry.export_traces( - resource_spans=[ - OtelResourceSpan( - resource=OtelResource( - attributes=[ - OtelAttribute( - key="service.name", - value=OtelAttributeValue( - string_value="my-service", - ), - ), - OtelAttribute( - key="service.version", - value=OtelAttributeValue( - string_value="1.0.0", - ), - ), - ], - ), - scope_spans=[ - OtelScopeSpan( - scope=OtelScope( - name="langfuse-sdk", - version="2.60.3", - ), - spans=[ - OtelSpan( - trace_id="0123456789abcdef0123456789abcdef", - span_id="0123456789abcdef", - name="my-operation", - kind=1, - start_time_unix_nano="1747872000000000000", - end_time_unix_nano="1747872001000000000", - attributes=[ - OtelAttribute( - key="langfuse.observation.type", - value=OtelAttributeValue( - string_value="generation", - ), - ) - ], - status={}, - ) - ], - ) - ], - ) - ], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**resource_spans:** `typing.Sequence[OtelResourceSpan]` — Array of resource spans containing trace data as defined in the OTLP specification - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Organizations -
client.organizations.get_organization_memberships() -
-
- -#### 📝 Description - -
-
- -
-
- -Get all memberships for the organization associated with the API key (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.organizations.get_organization_memberships() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.update_organization_membership(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create or update a membership for the organization associated with the API key (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import MembershipRequest, MembershipRole -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.organizations.update_organization_membership( - request=MembershipRequest( - user_id="userId", - role=MembershipRole.OWNER, - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `MembershipRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.delete_organization_membership(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a membership from the organization associated with the API key (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import DeleteMembershipRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.organizations.delete_organization_membership( - request=DeleteMembershipRequest( - user_id="userId", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `DeleteMembershipRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.get_project_memberships(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get all memberships for a specific project (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.organizations.get_project_memberships( - project_id="projectId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**project_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.update_project_membership(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create or update a membership for a specific project (requires organization-scoped API key). The user must already be a member of the organization. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import MembershipRequest, MembershipRole -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.organizations.update_project_membership( - project_id="projectId", - request=MembershipRequest( - user_id="userId", - role=MembershipRole.OWNER, - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**project_id:** `str` - -
-
- -
-
- -**request:** `MembershipRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.delete_project_membership(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a membership from a specific project (requires organization-scoped API key). The user must be a member of the organization. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import DeleteMembershipRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.organizations.delete_project_membership( - project_id="projectId", - request=DeleteMembershipRequest( - user_id="userId", - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**project_id:** `str` - -
-
- -
-
- -**request:** `DeleteMembershipRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.get_organization_projects() -
-
- -#### 📝 Description - -
-
- -
-
- -Get all projects for the organization associated with the API key (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.organizations.get_organization_projects() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.organizations.get_organization_api_keys() -
-
- -#### 📝 Description - -
-
- -
-
- -Get all API keys for the organization associated with the API key (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.organizations.get_organization_api_keys() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Projects -
client.projects.get() -
-
- -#### 📝 Description - -
-
- -
-
- -Get Project associated with API key (requires project-scoped API key). You can use GET /api/public/organizations/projects to get all projects with an organization-scoped key. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.projects.get() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.projects.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a new project (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.projects.create( - name="name", - retention=1, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**name:** `str` - -
-
- -
-
- -**retention:** `int` — Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. - -
-
- -
-
- -**metadata:** `typing.Optional[typing.Dict[str, typing.Any]]` — Optional metadata for the project - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.projects.update(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update a project by ID (requires organization-scoped API key). -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.projects.update( - project_id="projectId", - name="name", - retention=1, -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**project_id:** `str` - -
-
- -
-
- -**name:** `str` - -
-
- -
-
- -**retention:** `int` — Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. - -
-
- -
-
- -**metadata:** `typing.Optional[typing.Dict[str, typing.Any]]` — Optional metadata for the project - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.projects.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a project by ID (requires organization-scoped API key). Project deletion is processed asynchronously. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.projects.delete( - project_id="projectId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**project_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.projects.get_api_keys(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get all API keys for a project (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.projects.get_api_keys( - project_id="projectId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**project_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.projects.create_api_key(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a new API key for a project (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.projects.create_api_key( - project_id="projectId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**project_id:** `str` - -
-
- -
-
- -**note:** `typing.Optional[str]` — Optional note for the API key - -
-
- -
-
- -**public_key:** `typing.Optional[str]` — Optional predefined public key. Must start with 'pk-lf-'. If provided, secretKey must also be provided. - -
-
- -
-
- -**secret_key:** `typing.Optional[str]` — Optional predefined secret key. Must start with 'sk-lf-'. If provided, publicKey must also be provided. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.projects.delete_api_key(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete an API key for a project (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.projects.delete_api_key( - project_id="projectId", - api_key_id="apiKeyId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**project_id:** `str` - -
-
- -
-
- -**api_key_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## PromptVersion -
client.prompt_version.update(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update labels for a specific prompt version -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.prompt_version.update( - name="name", - version=1, - new_labels=["newLabels", "newLabels"], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**name:** `str` - -The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), -the folder path must be URL encoded. - -
-
- -
-
- -**version:** `int` — Version of the prompt to update - -
-
- -
-
- -**new_labels:** `typing.Sequence[str]` — New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Prompts -
client.prompts.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a prompt -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.prompts.get( - prompt_name="promptName", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**prompt_name:** `str` - -The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), -the folder path must be URL encoded. - -
-
- -
-
- -**version:** `typing.Optional[int]` — Version of the prompt to be retrieved. - -
-
- -
-
- -**label:** `typing.Optional[str]` — Label of the prompt to be retrieved. Defaults to "production" if no label or version is set. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.prompts.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a list of prompt names with versions and labels -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.prompts.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**label:** `typing.Optional[str]` - -
-
- -
-
- -**tag:** `typing.Optional[str]` - -
-
- -
-
- -**page:** `typing.Optional[int]` — page number, starts at 1 - -
-
- -
-
- -**limit:** `typing.Optional[int]` — limit of items per page - -
-
- -
-
- -**from_updated_at:** `typing.Optional[dt.datetime]` — Optional filter to only include prompt versions created/updated on or after a certain datetime (ISO 8601) - -
-
- -
-
- -**to_updated_at:** `typing.Optional[dt.datetime]` — Optional filter to only include prompt versions created/updated before a certain datetime (ISO 8601) - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.prompts.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a new version for the prompt with the given `name` -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import ( - ChatMessageWithPlaceholders_Chatmessage, - CreatePromptRequest_Chat, -) -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.prompts.create( - request=CreatePromptRequest_Chat( - name="name", - prompt=[ - ChatMessageWithPlaceholders_Chatmessage( - role="role", - content="content", - ), - ChatMessageWithPlaceholders_Chatmessage( - role="role", - content="content", - ), - ], - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `CreatePromptRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.prompts.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete prompt versions. If neither version nor label is specified, all versions of the prompt are deleted. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.prompts.delete( - prompt_name="promptName", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**prompt_name:** `str` — The name of the prompt - -
-
- -
-
- -**label:** `typing.Optional[str]` — Optional label to filter deletion. If specified, deletes all prompt versions that have this label. - -
-
- -
-
- -**version:** `typing.Optional[int]` — Optional version to filter deletion. If specified, deletes only this specific version of the prompt. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Scim -
client.scim.get_service_provider_config() -
-
- -#### 📝 Description - -
-
- -
-
- -Get SCIM Service Provider Configuration (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.scim.get_service_provider_config() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.scim.get_resource_types() -
-
- -#### 📝 Description - -
-
- -
-
- -Get SCIM Resource Types (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.scim.get_resource_types() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.scim.get_schemas() -
-
- -#### 📝 Description - -
-
- -
-
- -Get SCIM Schemas (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.scim.get_schemas() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.scim.list_users(...) -
-
- -#### 📝 Description - -
-
- -
-
- -List users in the organization (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.scim.list_users() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**filter:** `typing.Optional[str]` — Filter expression (e.g. userName eq "value") - -
-
- -
-
- -**start_index:** `typing.Optional[int]` — 1-based index of the first result to return (default 1) - -
-
- -
-
- -**count:** `typing.Optional[int]` — Maximum number of results to return (default 100) - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.scim.create_user(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a new user in the organization (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import ScimName -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.scim.create_user( - user_name="userName", - name=ScimName(), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**user_name:** `str` — User's email address (required) - -
-
- -
-
- -**name:** `ScimName` — User's name information - -
-
- -
-
- -**emails:** `typing.Optional[typing.Sequence[ScimEmail]]` — User's email addresses - -
-
- -
-
- -**active:** `typing.Optional[bool]` — Whether the user is active - -
-
- -
-
- -**password:** `typing.Optional[str]` — Initial password for the user - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.scim.get_user(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a specific user by ID (requires organization-scoped API key) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.scim.get_user( - user_id="userId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**user_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.scim.delete_user(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Remove a user from the organization (requires organization-scoped API key). Note that this only removes the user from the organization but does not delete the user entity itself. -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.scim.delete_user( - user_id="userId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**user_id:** `str` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## ScoreConfigs -
client.score_configs.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a score configuration (config). Score configs are used to define the structure of scores -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import CreateScoreConfigRequest, ScoreDataType -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.score_configs.create( - request=CreateScoreConfigRequest( - name="name", - data_type=ScoreDataType.NUMERIC, - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `CreateScoreConfigRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.score_configs.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get all score configs -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.score_configs.get() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**page:** `typing.Optional[int]` — Page number, starts at 1. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.score_configs.get_by_id(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a score config -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.score_configs.get_by_id( - config_id="configId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**config_id:** `str` — The unique langfuse identifier of a score config - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.score_configs.update(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Update a score config -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import UpdateScoreConfigRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.score_configs.update( - config_id="configId", - request=UpdateScoreConfigRequest(), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**config_id:** `str` — The unique langfuse identifier of a score config - -
-
- -
-
- -**request:** `UpdateScoreConfigRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## ScoreV2 -
client.score_v_2.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a list of scores (supports both trace and session scores) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.score_v_2.get() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**page:** `typing.Optional[int]` — Page number, starts at 1. - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. - -
-
- -
-
- -**user_id:** `typing.Optional[str]` — Retrieve only scores with this userId associated to the trace. - -
-
- -
-
- -**name:** `typing.Optional[str]` — Retrieve only scores with this name. - -
-
- -
-
- -**from_timestamp:** `typing.Optional[dt.datetime]` — Optional filter to only include scores created on or after a certain datetime (ISO 8601) - -
-
- -
-
- -**to_timestamp:** `typing.Optional[dt.datetime]` — Optional filter to only include scores created before a certain datetime (ISO 8601) - -
-
- -
-
- -**environment:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Optional filter for scores where the environment is one of the provided values. - -
-
- -
-
- -**source:** `typing.Optional[ScoreSource]` — Retrieve only scores from a specific source. - -
-
- -
-
- -**operator:** `typing.Optional[str]` — Retrieve only scores with value. - -
-
- -
-
- -**value:** `typing.Optional[float]` — Retrieve only scores with value. - -
-
- -
-
- -**score_ids:** `typing.Optional[str]` — Comma-separated list of score IDs to limit the results to. - -
-
- -
-
- -**config_id:** `typing.Optional[str]` — Retrieve only scores with a specific configId. - -
-
- -
-
- -**session_id:** `typing.Optional[str]` — Retrieve only scores with a specific sessionId. - -
-
- -
-
- -**dataset_run_id:** `typing.Optional[str]` — Retrieve only scores with a specific datasetRunId. - -
-
- -
-
- -**trace_id:** `typing.Optional[str]` — Retrieve only scores with a specific traceId. - -
-
- -
-
- -**queue_id:** `typing.Optional[str]` — Retrieve only scores with a specific annotation queueId. - -
-
- -
-
- -**data_type:** `typing.Optional[ScoreDataType]` — Retrieve only scores with a specific dataType. - -
-
- -
-
- -**trace_tags:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Only scores linked to traces that include all of these tags will be returned. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.score_v_2.get_by_id(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a score (supports both trace and session scores) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.score_v_2.get_by_id( - score_id="scoreId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**score_id:** `str` — The unique langfuse identifier of a score - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Score -
client.score.create(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Create a score (supports both trace and session scores) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse import CreateScoreRequest -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.score.create( - request=CreateScoreRequest( - name="name", - value=1.1, - ), -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**request:** `CreateScoreRequest` - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.score.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a score (supports both trace and session scores) -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.score.delete( - score_id="scoreId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**score_id:** `str` — The unique langfuse identifier of a score - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Sessions -
client.sessions.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get sessions -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.sessions.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**page:** `typing.Optional[int]` — Page number, starts at 1 - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. - -
-
- -
-
- -**from_timestamp:** `typing.Optional[dt.datetime]` — Optional filter to only include sessions created on or after a certain datetime (ISO 8601) - -
-
- -
-
- -**to_timestamp:** `typing.Optional[dt.datetime]` — Optional filter to only include sessions created before a certain datetime (ISO 8601) - -
-
- -
-
- -**environment:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Optional filter for sessions where the environment is one of the provided values. - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.sessions.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a session. Please note that `traces` on this endpoint are not paginated, if you plan to fetch large sessions, consider `GET /api/public/traces?sessionId=` -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.sessions.get( - session_id="sessionId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**session_id:** `str` — The unique id of a session - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -## Trace -
client.trace.get(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get a specific trace -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.trace.get( - trace_id="traceId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**trace_id:** `str` — The unique langfuse identifier of a trace - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.trace.delete(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete a specific trace -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.trace.delete( - trace_id="traceId", -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**trace_id:** `str` — The unique langfuse identifier of the trace to delete - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.trace.list(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Get list of traces -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.trace.list() - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**page:** `typing.Optional[int]` — Page number, starts at 1 - -
-
- -
-
- -**limit:** `typing.Optional[int]` — Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. - -
-
- -
-
- -**user_id:** `typing.Optional[str]` - -
-
- -
-
- -**name:** `typing.Optional[str]` - -
-
- -
-
- -**session_id:** `typing.Optional[str]` - -
-
- -
-
- -**from_timestamp:** `typing.Optional[dt.datetime]` — Optional filter to only include traces with a trace.timestamp on or after a certain datetime (ISO 8601) - -
-
- -
-
- -**to_timestamp:** `typing.Optional[dt.datetime]` — Optional filter to only include traces with a trace.timestamp before a certain datetime (ISO 8601) - -
-
- -
-
- -**order_by:** `typing.Optional[str]` — Format of the string [field].[asc/desc]. Fields: id, timestamp, name, userId, release, version, public, bookmarked, sessionId. Example: timestamp.asc - -
-
- -
-
- -**tags:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Only traces that include all of these tags will be returned. - -
-
- -
-
- -**version:** `typing.Optional[str]` — Optional filter to only include traces with a certain version. - -
-
- -
-
- -**release:** `typing.Optional[str]` — Optional filter to only include traces with a certain release. - -
-
- -
-
- -**environment:** `typing.Optional[typing.Union[str, typing.Sequence[str]]]` — Optional filter for traces where the environment is one of the provided values. - -
-
- -
-
- -**fields:** `typing.Optional[str]` — Comma-separated list of fields to include in the response. Available field groups: 'core' (always included), 'io' (input, output, metadata), 'scores', 'observations', 'metrics'. If not specified, all fields are returned. Example: 'core,scores,metrics'. Note: Excluded 'observations' or 'scores' fields return empty arrays; excluded 'metrics' returns -1 for 'totalCost' and 'latency'. - -
-
- -
-
- -**filter:** `typing.Optional[str]` - -JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, sessionId, tags, version, release, environment, fromTimestamp, toTimestamp). - -## Filter Structure -Each filter condition has the following structure: -```json -[ - { - "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" - "column": string, // Required. Column to filter on (see available columns below) - "operator": string, // Required. Operator based on type: - // - datetime: ">", "<", ">=", "<=" - // - string: "=", "contains", "does not contain", "starts with", "ends with" - // - stringOptions: "any of", "none of" - // - categoryOptions: "any of", "none of" - // - arrayOptions: "any of", "none of", "all of" - // - number: "=", ">", "<", ">=", "<=" - // - stringObject: "=", "contains", "does not contain", "starts with", "ends with" - // - numberObject: "=", ">", "<", ">=", "<=" - // - boolean: "=", "<>" - // - null: "is null", "is not null" - "value": any, // Required (except for null type). Value to compare against. Type depends on filter type - "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata - } -] -``` - -## Available Columns - -### Core Trace Fields -- `id` (string) - Trace ID -- `name` (string) - Trace name -- `timestamp` (datetime) - Trace timestamp -- `userId` (string) - User ID -- `sessionId` (string) - Session ID -- `environment` (string) - Environment tag -- `version` (string) - Version tag -- `release` (string) - Release tag -- `tags` (arrayOptions) - Array of tags -- `bookmarked` (boolean) - Bookmark status - -### Structured Data -- `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys. - -### Aggregated Metrics (from observations) -These metrics are aggregated from all observations within the trace: -- `latency` (number) - Latency in seconds (time from first observation start to last observation end) -- `inputTokens` (number) - Total input tokens across all observations -- `outputTokens` (number) - Total output tokens across all observations -- `totalTokens` (number) - Total tokens (alias: `tokens`) -- `inputCost` (number) - Total input cost in USD -- `outputCost` (number) - Total output cost in USD -- `totalCost` (number) - Total cost in USD - -### Observation Level Aggregations -These fields aggregate observation levels within the trace: -- `level` (string) - Highest severity level (ERROR > WARNING > DEFAULT > DEBUG) -- `warningCount` (number) - Count of WARNING level observations -- `errorCount` (number) - Count of ERROR level observations -- `defaultCount` (number) - Count of DEFAULT level observations -- `debugCount` (number) - Count of DEBUG level observations - -### Scores (requires join with scores table) -- `scores_avg` (number) - Average of numeric scores (alias: `scores`) -- `score_categories` (categoryOptions) - Categorical score values - -## Filter Examples -```json -[ - { - "type": "datetime", - "column": "timestamp", - "operator": ">=", - "value": "2024-01-01T00:00:00Z" - }, - { - "type": "string", - "column": "userId", - "operator": "=", - "value": "user-123" - }, - { - "type": "number", - "column": "totalCost", - "operator": ">=", - "value": 0.01 - }, - { - "type": "arrayOptions", - "column": "tags", - "operator": "all of", - "value": ["production", "critical"] - }, - { - "type": "stringObject", - "column": "metadata", - "key": "customer_tier", - "operator": "=", - "value": "enterprise" - } -] -``` - -## Performance Notes -- Filtering on `userId`, `sessionId`, or `metadata` may enable skip indexes for better query performance -- Score filters require a join with the scores table and may impact query performance - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- -
client.trace.delete_multiple(...) -
-
- -#### 📝 Description - -
-
- -
-
- -Delete multiple traces -
-
-
-
- -#### 🔌 Usage - -
-
- -
-
- -```python -from langfuse.client import FernLangfuse - -client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", -) -client.trace.delete_multiple( - trace_ids=["traceIds", "traceIds"], -) - -``` -
-
-
-
- -#### ⚙️ Parameters - -
-
- -
-
- -**trace_ids:** `typing.Sequence[str]` — List of trace IDs to delete - -
-
- -
-
- -**request_options:** `typing.Optional[RequestOptions]` — Request-specific configuration. - -
-
-
-
- - -
-
-
- diff --git a/langfuse/api/resources/__init__.py b/langfuse/api/resources/__init__.py deleted file mode 100644 index d91362a28..000000000 --- a/langfuse/api/resources/__init__.py +++ /dev/null @@ -1,522 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from . import ( - annotation_queues, - blob_storage_integrations, - comments, - commons, - dataset_items, - dataset_run_items, - datasets, - health, - ingestion, - llm_connections, - media, - metrics, - models, - observations, - opentelemetry, - organizations, - projects, - prompt_version, - prompts, - scim, - score, - score_configs, - score_v_2, - sessions, - trace, - utils, -) -from .annotation_queues import ( - AnnotationQueue, - AnnotationQueueAssignmentRequest, - AnnotationQueueItem, - AnnotationQueueObjectType, - AnnotationQueueStatus, - CreateAnnotationQueueAssignmentResponse, - CreateAnnotationQueueItemRequest, - CreateAnnotationQueueRequest, - DeleteAnnotationQueueAssignmentResponse, - DeleteAnnotationQueueItemResponse, - PaginatedAnnotationQueueItems, - PaginatedAnnotationQueues, - UpdateAnnotationQueueItemRequest, -) -from .blob_storage_integrations import ( - BlobStorageExportFrequency, - BlobStorageExportMode, - BlobStorageIntegrationDeletionResponse, - BlobStorageIntegrationFileType, - BlobStorageIntegrationResponse, - BlobStorageIntegrationType, - BlobStorageIntegrationsResponse, - CreateBlobStorageIntegrationRequest, -) -from .comments import CreateCommentRequest, CreateCommentResponse, GetCommentsResponse -from .commons import ( - AccessDeniedError, - BaseScore, - BaseScoreV1, - BooleanScore, - BooleanScoreV1, - CategoricalScore, - CategoricalScoreV1, - Comment, - CommentObjectType, - ConfigCategory, - CreateScoreValue, - Dataset, - DatasetItem, - DatasetRun, - DatasetRunItem, - DatasetRunWithItems, - DatasetStatus, - Error, - MapValue, - MethodNotAllowedError, - Model, - ModelPrice, - ModelUsageUnit, - NotFoundError, - NumericScore, - NumericScoreV1, - Observation, - ObservationLevel, - ObservationsView, - PricingTier, - PricingTierCondition, - PricingTierInput, - PricingTierOperator, - Score, - ScoreConfig, - ScoreDataType, - ScoreSource, - ScoreV1, - ScoreV1_Boolean, - ScoreV1_Categorical, - ScoreV1_Numeric, - Score_Boolean, - Score_Categorical, - Score_Numeric, - Session, - SessionWithTraces, - Trace, - TraceWithDetails, - TraceWithFullDetails, - UnauthorizedError, - Usage, -) -from .dataset_items import ( - CreateDatasetItemRequest, - DeleteDatasetItemResponse, - PaginatedDatasetItems, -) -from .dataset_run_items import CreateDatasetRunItemRequest, PaginatedDatasetRunItems -from .datasets import ( - CreateDatasetRequest, - DeleteDatasetRunResponse, - PaginatedDatasetRuns, - PaginatedDatasets, -) -from .health import HealthResponse, ServiceUnavailableError -from .ingestion import ( - BaseEvent, - CreateEventBody, - CreateEventEvent, - CreateGenerationBody, - CreateGenerationEvent, - CreateObservationEvent, - CreateSpanBody, - CreateSpanEvent, - IngestionError, - IngestionEvent, - IngestionEvent_EventCreate, - IngestionEvent_GenerationCreate, - IngestionEvent_GenerationUpdate, - IngestionEvent_ObservationCreate, - IngestionEvent_ObservationUpdate, - IngestionEvent_ScoreCreate, - IngestionEvent_SdkLog, - IngestionEvent_SpanCreate, - IngestionEvent_SpanUpdate, - IngestionEvent_TraceCreate, - IngestionResponse, - IngestionSuccess, - IngestionUsage, - ObservationBody, - ObservationType, - OpenAiCompletionUsageSchema, - OpenAiResponseUsageSchema, - OpenAiUsage, - OptionalObservationBody, - ScoreBody, - ScoreEvent, - SdkLogBody, - SdkLogEvent, - TraceBody, - TraceEvent, - UpdateEventBody, - UpdateGenerationBody, - UpdateGenerationEvent, - UpdateObservationEvent, - UpdateSpanBody, - UpdateSpanEvent, - UsageDetails, -) -from .llm_connections import ( - LlmAdapter, - LlmConnection, - PaginatedLlmConnections, - UpsertLlmConnectionRequest, -) -from .media import ( - GetMediaResponse, - GetMediaUploadUrlRequest, - GetMediaUploadUrlResponse, - MediaContentType, - PatchMediaBody, -) -from .metrics import MetricsResponse -from .models import CreateModelRequest, PaginatedModels -from .observations import Observations, ObservationsViews -from .opentelemetry import ( - OtelAttribute, - OtelAttributeValue, - OtelResource, - OtelResourceSpan, - OtelScope, - OtelScopeSpan, - OtelSpan, - OtelTraceResponse, -) -from .organizations import ( - DeleteMembershipRequest, - MembershipDeletionResponse, - MembershipRequest, - MembershipResponse, - MembershipRole, - MembershipsResponse, - OrganizationApiKey, - OrganizationApiKeysResponse, - OrganizationProject, - OrganizationProjectsResponse, -) -from .projects import ( - ApiKeyDeletionResponse, - ApiKeyList, - ApiKeyResponse, - ApiKeySummary, - Project, - ProjectDeletionResponse, - Projects, -) -from .prompts import ( - BasePrompt, - ChatMessage, - ChatMessageWithPlaceholders, - ChatMessageWithPlaceholders_Chatmessage, - ChatMessageWithPlaceholders_Placeholder, - ChatPrompt, - CreateChatPromptRequest, - CreatePromptRequest, - CreatePromptRequest_Chat, - CreatePromptRequest_Text, - CreateTextPromptRequest, - PlaceholderMessage, - Prompt, - PromptMeta, - PromptMetaListResponse, - PromptType, - Prompt_Chat, - Prompt_Text, - TextPrompt, -) -from .scim import ( - AuthenticationScheme, - BulkConfig, - EmptyResponse, - FilterConfig, - ResourceMeta, - ResourceType, - ResourceTypesResponse, - SchemaExtension, - SchemaResource, - SchemasResponse, - ScimEmail, - ScimFeatureSupport, - ScimName, - ScimUser, - ScimUsersListResponse, - ServiceProviderConfig, - UserMeta, -) -from .score import CreateScoreRequest, CreateScoreResponse -from .score_configs import ( - CreateScoreConfigRequest, - ScoreConfigs, - UpdateScoreConfigRequest, -) -from .score_v_2 import ( - GetScoresResponse, - GetScoresResponseData, - GetScoresResponseDataBoolean, - GetScoresResponseDataCategorical, - GetScoresResponseDataNumeric, - GetScoresResponseData_Boolean, - GetScoresResponseData_Categorical, - GetScoresResponseData_Numeric, - GetScoresResponseTraceData, -) -from .sessions import PaginatedSessions -from .trace import DeleteTraceResponse, Sort, Traces - -__all__ = [ - "AccessDeniedError", - "AnnotationQueue", - "AnnotationQueueAssignmentRequest", - "AnnotationQueueItem", - "AnnotationQueueObjectType", - "AnnotationQueueStatus", - "ApiKeyDeletionResponse", - "ApiKeyList", - "ApiKeyResponse", - "ApiKeySummary", - "AuthenticationScheme", - "BaseEvent", - "BasePrompt", - "BaseScore", - "BaseScoreV1", - "BlobStorageExportFrequency", - "BlobStorageExportMode", - "BlobStorageIntegrationDeletionResponse", - "BlobStorageIntegrationFileType", - "BlobStorageIntegrationResponse", - "BlobStorageIntegrationType", - "BlobStorageIntegrationsResponse", - "BooleanScore", - "BooleanScoreV1", - "BulkConfig", - "CategoricalScore", - "CategoricalScoreV1", - "ChatMessage", - "ChatMessageWithPlaceholders", - "ChatMessageWithPlaceholders_Chatmessage", - "ChatMessageWithPlaceholders_Placeholder", - "ChatPrompt", - "Comment", - "CommentObjectType", - "ConfigCategory", - "CreateAnnotationQueueAssignmentResponse", - "CreateAnnotationQueueItemRequest", - "CreateAnnotationQueueRequest", - "CreateBlobStorageIntegrationRequest", - "CreateChatPromptRequest", - "CreateCommentRequest", - "CreateCommentResponse", - "CreateDatasetItemRequest", - "CreateDatasetRequest", - "CreateDatasetRunItemRequest", - "CreateEventBody", - "CreateEventEvent", - "CreateGenerationBody", - "CreateGenerationEvent", - "CreateModelRequest", - "CreateObservationEvent", - "CreatePromptRequest", - "CreatePromptRequest_Chat", - "CreatePromptRequest_Text", - "CreateScoreConfigRequest", - "CreateScoreRequest", - "CreateScoreResponse", - "CreateScoreValue", - "CreateSpanBody", - "CreateSpanEvent", - "CreateTextPromptRequest", - "Dataset", - "DatasetItem", - "DatasetRun", - "DatasetRunItem", - "DatasetRunWithItems", - "DatasetStatus", - "DeleteAnnotationQueueAssignmentResponse", - "DeleteAnnotationQueueItemResponse", - "DeleteDatasetItemResponse", - "DeleteDatasetRunResponse", - "DeleteMembershipRequest", - "DeleteTraceResponse", - "EmptyResponse", - "Error", - "FilterConfig", - "GetCommentsResponse", - "GetMediaResponse", - "GetMediaUploadUrlRequest", - "GetMediaUploadUrlResponse", - "GetScoresResponse", - "GetScoresResponseData", - "GetScoresResponseDataBoolean", - "GetScoresResponseDataCategorical", - "GetScoresResponseDataNumeric", - "GetScoresResponseData_Boolean", - "GetScoresResponseData_Categorical", - "GetScoresResponseData_Numeric", - "GetScoresResponseTraceData", - "HealthResponse", - "IngestionError", - "IngestionEvent", - "IngestionEvent_EventCreate", - "IngestionEvent_GenerationCreate", - "IngestionEvent_GenerationUpdate", - "IngestionEvent_ObservationCreate", - "IngestionEvent_ObservationUpdate", - "IngestionEvent_ScoreCreate", - "IngestionEvent_SdkLog", - "IngestionEvent_SpanCreate", - "IngestionEvent_SpanUpdate", - "IngestionEvent_TraceCreate", - "IngestionResponse", - "IngestionSuccess", - "IngestionUsage", - "LlmAdapter", - "LlmConnection", - "MapValue", - "MediaContentType", - "MembershipDeletionResponse", - "MembershipRequest", - "MembershipResponse", - "MembershipRole", - "MembershipsResponse", - "MethodNotAllowedError", - "MetricsResponse", - "Model", - "ModelPrice", - "ModelUsageUnit", - "NotFoundError", - "NumericScore", - "NumericScoreV1", - "Observation", - "ObservationBody", - "ObservationLevel", - "ObservationType", - "Observations", - "ObservationsView", - "ObservationsViews", - "OpenAiCompletionUsageSchema", - "OpenAiResponseUsageSchema", - "OpenAiUsage", - "OptionalObservationBody", - "OrganizationApiKey", - "OrganizationApiKeysResponse", - "OrganizationProject", - "OrganizationProjectsResponse", - "OtelAttribute", - "OtelAttributeValue", - "OtelResource", - "OtelResourceSpan", - "OtelScope", - "OtelScopeSpan", - "OtelSpan", - "OtelTraceResponse", - "PaginatedAnnotationQueueItems", - "PaginatedAnnotationQueues", - "PaginatedDatasetItems", - "PaginatedDatasetRunItems", - "PaginatedDatasetRuns", - "PaginatedDatasets", - "PaginatedLlmConnections", - "PaginatedModels", - "PaginatedSessions", - "PatchMediaBody", - "PlaceholderMessage", - "PricingTier", - "PricingTierCondition", - "PricingTierInput", - "PricingTierOperator", - "Project", - "ProjectDeletionResponse", - "Projects", - "Prompt", - "PromptMeta", - "PromptMetaListResponse", - "PromptType", - "Prompt_Chat", - "Prompt_Text", - "ResourceMeta", - "ResourceType", - "ResourceTypesResponse", - "SchemaExtension", - "SchemaResource", - "SchemasResponse", - "ScimEmail", - "ScimFeatureSupport", - "ScimName", - "ScimUser", - "ScimUsersListResponse", - "Score", - "ScoreBody", - "ScoreConfig", - "ScoreConfigs", - "ScoreDataType", - "ScoreEvent", - "ScoreSource", - "ScoreV1", - "ScoreV1_Boolean", - "ScoreV1_Categorical", - "ScoreV1_Numeric", - "Score_Boolean", - "Score_Categorical", - "Score_Numeric", - "SdkLogBody", - "SdkLogEvent", - "ServiceProviderConfig", - "ServiceUnavailableError", - "Session", - "SessionWithTraces", - "Sort", - "TextPrompt", - "Trace", - "TraceBody", - "TraceEvent", - "TraceWithDetails", - "TraceWithFullDetails", - "Traces", - "UnauthorizedError", - "UpdateAnnotationQueueItemRequest", - "UpdateEventBody", - "UpdateGenerationBody", - "UpdateGenerationEvent", - "UpdateObservationEvent", - "UpdateScoreConfigRequest", - "UpdateSpanBody", - "UpdateSpanEvent", - "UpsertLlmConnectionRequest", - "Usage", - "UsageDetails", - "UserMeta", - "annotation_queues", - "blob_storage_integrations", - "comments", - "commons", - "dataset_items", - "dataset_run_items", - "datasets", - "health", - "ingestion", - "llm_connections", - "media", - "metrics", - "models", - "observations", - "opentelemetry", - "organizations", - "projects", - "prompt_version", - "prompts", - "scim", - "score", - "score_configs", - "score_v_2", - "sessions", - "trace", - "utils", -] diff --git a/langfuse/api/resources/annotation_queues/__init__.py b/langfuse/api/resources/annotation_queues/__init__.py deleted file mode 100644 index eed891727..000000000 --- a/langfuse/api/resources/annotation_queues/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - AnnotationQueue, - AnnotationQueueAssignmentRequest, - AnnotationQueueItem, - AnnotationQueueObjectType, - AnnotationQueueStatus, - CreateAnnotationQueueAssignmentResponse, - CreateAnnotationQueueItemRequest, - CreateAnnotationQueueRequest, - DeleteAnnotationQueueAssignmentResponse, - DeleteAnnotationQueueItemResponse, - PaginatedAnnotationQueueItems, - PaginatedAnnotationQueues, - UpdateAnnotationQueueItemRequest, -) - -__all__ = [ - "AnnotationQueue", - "AnnotationQueueAssignmentRequest", - "AnnotationQueueItem", - "AnnotationQueueObjectType", - "AnnotationQueueStatus", - "CreateAnnotationQueueAssignmentResponse", - "CreateAnnotationQueueItemRequest", - "CreateAnnotationQueueRequest", - "DeleteAnnotationQueueAssignmentResponse", - "DeleteAnnotationQueueItemResponse", - "PaginatedAnnotationQueueItems", - "PaginatedAnnotationQueues", - "UpdateAnnotationQueueItemRequest", -] diff --git a/langfuse/api/resources/annotation_queues/client.py b/langfuse/api/resources/annotation_queues/client.py deleted file mode 100644 index 97c7c2216..000000000 --- a/langfuse/api/resources/annotation_queues/client.py +++ /dev/null @@ -1,1642 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from .types.annotation_queue import AnnotationQueue -from .types.annotation_queue_assignment_request import AnnotationQueueAssignmentRequest -from .types.annotation_queue_item import AnnotationQueueItem -from .types.annotation_queue_status import AnnotationQueueStatus -from .types.create_annotation_queue_assignment_response import ( - CreateAnnotationQueueAssignmentResponse, -) -from .types.create_annotation_queue_item_request import CreateAnnotationQueueItemRequest -from .types.create_annotation_queue_request import CreateAnnotationQueueRequest -from .types.delete_annotation_queue_assignment_response import ( - DeleteAnnotationQueueAssignmentResponse, -) -from .types.delete_annotation_queue_item_response import ( - DeleteAnnotationQueueItemResponse, -) -from .types.paginated_annotation_queue_items import PaginatedAnnotationQueueItems -from .types.paginated_annotation_queues import PaginatedAnnotationQueues -from .types.update_annotation_queue_item_request import UpdateAnnotationQueueItemRequest - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class AnnotationQueuesClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def list_queues( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedAnnotationQueues: - """ - Get all annotation queues - - Parameters - ---------- - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedAnnotationQueues - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.annotation_queues.list_queues() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/annotation-queues", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - PaginatedAnnotationQueues, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create_queue( - self, - *, - request: CreateAnnotationQueueRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> AnnotationQueue: - """ - Create an annotation queue - - Parameters - ---------- - request : CreateAnnotationQueueRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AnnotationQueue - - Examples - -------- - from langfuse import CreateAnnotationQueueRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.annotation_queues.create_queue( - request=CreateAnnotationQueueRequest( - name="name", - score_config_ids=["scoreConfigIds", "scoreConfigIds"], - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/annotation-queues", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(AnnotationQueue, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_queue( - self, queue_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AnnotationQueue: - """ - Get an annotation queue by ID - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AnnotationQueue - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.annotation_queues.get_queue( - queue_id="queueId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(AnnotationQueue, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_queue_items( - self, - queue_id: str, - *, - status: typing.Optional[AnnotationQueueStatus] = None, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedAnnotationQueueItems: - """ - Get items for a specific annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - status : typing.Optional[AnnotationQueueStatus] - Filter by status - - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedAnnotationQueueItems - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.annotation_queues.list_queue_items( - queue_id="queueId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items", - method="GET", - params={"status": status, "page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - PaginatedAnnotationQueueItems, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_queue_item( - self, - queue_id: str, - item_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> AnnotationQueueItem: - """ - Get a specific item from an annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - item_id : str - The unique identifier of the annotation queue item - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AnnotationQueueItem - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.annotation_queues.get_queue_item( - queue_id="queueId", - item_id="itemId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(AnnotationQueueItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create_queue_item( - self, - queue_id: str, - *, - request: CreateAnnotationQueueItemRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> AnnotationQueueItem: - """ - Add an item to an annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - request : CreateAnnotationQueueItemRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AnnotationQueueItem - - Examples - -------- - from langfuse import AnnotationQueueObjectType, CreateAnnotationQueueItemRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.annotation_queues.create_queue_item( - queue_id="queueId", - request=CreateAnnotationQueueItemRequest( - object_id="objectId", - object_type=AnnotationQueueObjectType.TRACE, - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(AnnotationQueueItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def update_queue_item( - self, - queue_id: str, - item_id: str, - *, - request: UpdateAnnotationQueueItemRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> AnnotationQueueItem: - """ - Update an annotation queue item - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - item_id : str - The unique identifier of the annotation queue item - - request : UpdateAnnotationQueueItemRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AnnotationQueueItem - - Examples - -------- - from langfuse import UpdateAnnotationQueueItemRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.annotation_queues.update_queue_item( - queue_id="queueId", - item_id="itemId", - request=UpdateAnnotationQueueItemRequest(), - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", - method="PATCH", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(AnnotationQueueItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete_queue_item( - self, - queue_id: str, - item_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> DeleteAnnotationQueueItemResponse: - """ - Remove an item from an annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - item_id : str - The unique identifier of the annotation queue item - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteAnnotationQueueItemResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.annotation_queues.delete_queue_item( - queue_id="queueId", - item_id="itemId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - DeleteAnnotationQueueItemResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create_queue_assignment( - self, - queue_id: str, - *, - request: AnnotationQueueAssignmentRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateAnnotationQueueAssignmentResponse: - """ - Create an assignment for a user to an annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - request : AnnotationQueueAssignmentRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateAnnotationQueueAssignmentResponse - - Examples - -------- - from langfuse import AnnotationQueueAssignmentRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.annotation_queues.create_queue_assignment( - queue_id="queueId", - request=AnnotationQueueAssignmentRequest( - user_id="userId", - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/assignments", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - CreateAnnotationQueueAssignmentResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete_queue_assignment( - self, - queue_id: str, - *, - request: AnnotationQueueAssignmentRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> DeleteAnnotationQueueAssignmentResponse: - """ - Delete an assignment for a user to an annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - request : AnnotationQueueAssignmentRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteAnnotationQueueAssignmentResponse - - Examples - -------- - from langfuse import AnnotationQueueAssignmentRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.annotation_queues.delete_queue_assignment( - queue_id="queueId", - request=AnnotationQueueAssignmentRequest( - user_id="userId", - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/assignments", - method="DELETE", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - DeleteAnnotationQueueAssignmentResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncAnnotationQueuesClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list_queues( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedAnnotationQueues: - """ - Get all annotation queues - - Parameters - ---------- - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedAnnotationQueues - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.annotation_queues.list_queues() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/annotation-queues", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - PaginatedAnnotationQueues, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create_queue( - self, - *, - request: CreateAnnotationQueueRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> AnnotationQueue: - """ - Create an annotation queue - - Parameters - ---------- - request : CreateAnnotationQueueRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AnnotationQueue - - Examples - -------- - import asyncio - - from langfuse import CreateAnnotationQueueRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.annotation_queues.create_queue( - request=CreateAnnotationQueueRequest( - name="name", - score_config_ids=["scoreConfigIds", "scoreConfigIds"], - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/annotation-queues", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(AnnotationQueue, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_queue( - self, queue_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> AnnotationQueue: - """ - Get an annotation queue by ID - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AnnotationQueue - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.annotation_queues.get_queue( - queue_id="queueId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(AnnotationQueue, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list_queue_items( - self, - queue_id: str, - *, - status: typing.Optional[AnnotationQueueStatus] = None, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedAnnotationQueueItems: - """ - Get items for a specific annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - status : typing.Optional[AnnotationQueueStatus] - Filter by status - - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedAnnotationQueueItems - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.annotation_queues.list_queue_items( - queue_id="queueId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items", - method="GET", - params={"status": status, "page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - PaginatedAnnotationQueueItems, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_queue_item( - self, - queue_id: str, - item_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> AnnotationQueueItem: - """ - Get a specific item from an annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - item_id : str - The unique identifier of the annotation queue item - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AnnotationQueueItem - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.annotation_queues.get_queue_item( - queue_id="queueId", - item_id="itemId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(AnnotationQueueItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create_queue_item( - self, - queue_id: str, - *, - request: CreateAnnotationQueueItemRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> AnnotationQueueItem: - """ - Add an item to an annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - request : CreateAnnotationQueueItemRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AnnotationQueueItem - - Examples - -------- - import asyncio - - from langfuse import AnnotationQueueObjectType, CreateAnnotationQueueItemRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.annotation_queues.create_queue_item( - queue_id="queueId", - request=CreateAnnotationQueueItemRequest( - object_id="objectId", - object_type=AnnotationQueueObjectType.TRACE, - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(AnnotationQueueItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def update_queue_item( - self, - queue_id: str, - item_id: str, - *, - request: UpdateAnnotationQueueItemRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> AnnotationQueueItem: - """ - Update an annotation queue item - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - item_id : str - The unique identifier of the annotation queue item - - request : UpdateAnnotationQueueItemRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - AnnotationQueueItem - - Examples - -------- - import asyncio - - from langfuse import UpdateAnnotationQueueItemRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.annotation_queues.update_queue_item( - queue_id="queueId", - item_id="itemId", - request=UpdateAnnotationQueueItemRequest(), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", - method="PATCH", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(AnnotationQueueItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete_queue_item( - self, - queue_id: str, - item_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> DeleteAnnotationQueueItemResponse: - """ - Remove an item from an annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - item_id : str - The unique identifier of the annotation queue item - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteAnnotationQueueItemResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.annotation_queues.delete_queue_item( - queue_id="queueId", - item_id="itemId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/items/{jsonable_encoder(item_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - DeleteAnnotationQueueItemResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create_queue_assignment( - self, - queue_id: str, - *, - request: AnnotationQueueAssignmentRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateAnnotationQueueAssignmentResponse: - """ - Create an assignment for a user to an annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - request : AnnotationQueueAssignmentRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateAnnotationQueueAssignmentResponse - - Examples - -------- - import asyncio - - from langfuse import AnnotationQueueAssignmentRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.annotation_queues.create_queue_assignment( - queue_id="queueId", - request=AnnotationQueueAssignmentRequest( - user_id="userId", - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/assignments", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - CreateAnnotationQueueAssignmentResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete_queue_assignment( - self, - queue_id: str, - *, - request: AnnotationQueueAssignmentRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> DeleteAnnotationQueueAssignmentResponse: - """ - Delete an assignment for a user to an annotation queue - - Parameters - ---------- - queue_id : str - The unique identifier of the annotation queue - - request : AnnotationQueueAssignmentRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteAnnotationQueueAssignmentResponse - - Examples - -------- - import asyncio - - from langfuse import AnnotationQueueAssignmentRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.annotation_queues.delete_queue_assignment( - queue_id="queueId", - request=AnnotationQueueAssignmentRequest( - user_id="userId", - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/annotation-queues/{jsonable_encoder(queue_id)}/assignments", - method="DELETE", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - DeleteAnnotationQueueAssignmentResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/annotation_queues/types/__init__.py b/langfuse/api/resources/annotation_queues/types/__init__.py deleted file mode 100644 index 9f9ce37dd..000000000 --- a/langfuse/api/resources/annotation_queues/types/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .annotation_queue import AnnotationQueue -from .annotation_queue_assignment_request import AnnotationQueueAssignmentRequest -from .annotation_queue_item import AnnotationQueueItem -from .annotation_queue_object_type import AnnotationQueueObjectType -from .annotation_queue_status import AnnotationQueueStatus -from .create_annotation_queue_assignment_response import ( - CreateAnnotationQueueAssignmentResponse, -) -from .create_annotation_queue_item_request import CreateAnnotationQueueItemRequest -from .create_annotation_queue_request import CreateAnnotationQueueRequest -from .delete_annotation_queue_assignment_response import ( - DeleteAnnotationQueueAssignmentResponse, -) -from .delete_annotation_queue_item_response import DeleteAnnotationQueueItemResponse -from .paginated_annotation_queue_items import PaginatedAnnotationQueueItems -from .paginated_annotation_queues import PaginatedAnnotationQueues -from .update_annotation_queue_item_request import UpdateAnnotationQueueItemRequest - -__all__ = [ - "AnnotationQueue", - "AnnotationQueueAssignmentRequest", - "AnnotationQueueItem", - "AnnotationQueueObjectType", - "AnnotationQueueStatus", - "CreateAnnotationQueueAssignmentResponse", - "CreateAnnotationQueueItemRequest", - "CreateAnnotationQueueRequest", - "DeleteAnnotationQueueAssignmentResponse", - "DeleteAnnotationQueueItemResponse", - "PaginatedAnnotationQueueItems", - "PaginatedAnnotationQueues", - "UpdateAnnotationQueueItemRequest", -] diff --git a/langfuse/api/resources/annotation_queues/types/annotation_queue.py b/langfuse/api/resources/annotation_queues/types/annotation_queue.py deleted file mode 100644 index c4cc23282..000000000 --- a/langfuse/api/resources/annotation_queues/types/annotation_queue.py +++ /dev/null @@ -1,49 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class AnnotationQueue(pydantic_v1.BaseModel): - id: str - name: str - description: typing.Optional[str] = None - score_config_ids: typing.List[str] = pydantic_v1.Field(alias="scoreConfigIds") - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/annotation_queues/types/annotation_queue_assignment_request.py b/langfuse/api/resources/annotation_queues/types/annotation_queue_assignment_request.py deleted file mode 100644 index aa3980438..000000000 --- a/langfuse/api/resources/annotation_queues/types/annotation_queue_assignment_request.py +++ /dev/null @@ -1,44 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class AnnotationQueueAssignmentRequest(pydantic_v1.BaseModel): - user_id: str = pydantic_v1.Field(alias="userId") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/annotation_queues/types/annotation_queue_item.py b/langfuse/api/resources/annotation_queues/types/annotation_queue_item.py deleted file mode 100644 index e88829a1f..000000000 --- a/langfuse/api/resources/annotation_queues/types/annotation_queue_item.py +++ /dev/null @@ -1,55 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .annotation_queue_object_type import AnnotationQueueObjectType -from .annotation_queue_status import AnnotationQueueStatus - - -class AnnotationQueueItem(pydantic_v1.BaseModel): - id: str - queue_id: str = pydantic_v1.Field(alias="queueId") - object_id: str = pydantic_v1.Field(alias="objectId") - object_type: AnnotationQueueObjectType = pydantic_v1.Field(alias="objectType") - status: AnnotationQueueStatus - completed_at: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="completedAt", default=None - ) - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/annotation_queues/types/annotation_queue_object_type.py b/langfuse/api/resources/annotation_queues/types/annotation_queue_object_type.py deleted file mode 100644 index 6e63a7015..000000000 --- a/langfuse/api/resources/annotation_queues/types/annotation_queue_object_type.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class AnnotationQueueObjectType(str, enum.Enum): - TRACE = "TRACE" - OBSERVATION = "OBSERVATION" - SESSION = "SESSION" - - def visit( - self, - trace: typing.Callable[[], T_Result], - observation: typing.Callable[[], T_Result], - session: typing.Callable[[], T_Result], - ) -> T_Result: - if self is AnnotationQueueObjectType.TRACE: - return trace() - if self is AnnotationQueueObjectType.OBSERVATION: - return observation() - if self is AnnotationQueueObjectType.SESSION: - return session() diff --git a/langfuse/api/resources/annotation_queues/types/annotation_queue_status.py b/langfuse/api/resources/annotation_queues/types/annotation_queue_status.py deleted file mode 100644 index cf075f38a..000000000 --- a/langfuse/api/resources/annotation_queues/types/annotation_queue_status.py +++ /dev/null @@ -1,21 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class AnnotationQueueStatus(str, enum.Enum): - PENDING = "PENDING" - COMPLETED = "COMPLETED" - - def visit( - self, - pending: typing.Callable[[], T_Result], - completed: typing.Callable[[], T_Result], - ) -> T_Result: - if self is AnnotationQueueStatus.PENDING: - return pending() - if self is AnnotationQueueStatus.COMPLETED: - return completed() diff --git a/langfuse/api/resources/annotation_queues/types/create_annotation_queue_assignment_response.py b/langfuse/api/resources/annotation_queues/types/create_annotation_queue_assignment_response.py deleted file mode 100644 index ae6a46862..000000000 --- a/langfuse/api/resources/annotation_queues/types/create_annotation_queue_assignment_response.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class CreateAnnotationQueueAssignmentResponse(pydantic_v1.BaseModel): - user_id: str = pydantic_v1.Field(alias="userId") - queue_id: str = pydantic_v1.Field(alias="queueId") - project_id: str = pydantic_v1.Field(alias="projectId") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/annotation_queues/types/create_annotation_queue_item_request.py b/langfuse/api/resources/annotation_queues/types/create_annotation_queue_item_request.py deleted file mode 100644 index cbf257f29..000000000 --- a/langfuse/api/resources/annotation_queues/types/create_annotation_queue_item_request.py +++ /dev/null @@ -1,51 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .annotation_queue_object_type import AnnotationQueueObjectType -from .annotation_queue_status import AnnotationQueueStatus - - -class CreateAnnotationQueueItemRequest(pydantic_v1.BaseModel): - object_id: str = pydantic_v1.Field(alias="objectId") - object_type: AnnotationQueueObjectType = pydantic_v1.Field(alias="objectType") - status: typing.Optional[AnnotationQueueStatus] = pydantic_v1.Field(default=None) - """ - Defaults to PENDING for new queue items - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/annotation_queues/types/create_annotation_queue_request.py b/langfuse/api/resources/annotation_queues/types/create_annotation_queue_request.py deleted file mode 100644 index 7f793cea2..000000000 --- a/langfuse/api/resources/annotation_queues/types/create_annotation_queue_request.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class CreateAnnotationQueueRequest(pydantic_v1.BaseModel): - name: str - description: typing.Optional[str] = None - score_config_ids: typing.List[str] = pydantic_v1.Field(alias="scoreConfigIds") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/annotation_queues/types/delete_annotation_queue_assignment_response.py b/langfuse/api/resources/annotation_queues/types/delete_annotation_queue_assignment_response.py deleted file mode 100644 index e348d546c..000000000 --- a/langfuse/api/resources/annotation_queues/types/delete_annotation_queue_assignment_response.py +++ /dev/null @@ -1,42 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class DeleteAnnotationQueueAssignmentResponse(pydantic_v1.BaseModel): - success: bool - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/annotation_queues/types/delete_annotation_queue_item_response.py b/langfuse/api/resources/annotation_queues/types/delete_annotation_queue_item_response.py deleted file mode 100644 index a412c85b7..000000000 --- a/langfuse/api/resources/annotation_queues/types/delete_annotation_queue_item_response.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class DeleteAnnotationQueueItemResponse(pydantic_v1.BaseModel): - success: bool - message: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/annotation_queues/types/paginated_annotation_queue_items.py b/langfuse/api/resources/annotation_queues/types/paginated_annotation_queue_items.py deleted file mode 100644 index 587188d89..000000000 --- a/langfuse/api/resources/annotation_queues/types/paginated_annotation_queue_items.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...utils.resources.pagination.types.meta_response import MetaResponse -from .annotation_queue_item import AnnotationQueueItem - - -class PaginatedAnnotationQueueItems(pydantic_v1.BaseModel): - data: typing.List[AnnotationQueueItem] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/annotation_queues/types/paginated_annotation_queues.py b/langfuse/api/resources/annotation_queues/types/paginated_annotation_queues.py deleted file mode 100644 index aba338414..000000000 --- a/langfuse/api/resources/annotation_queues/types/paginated_annotation_queues.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...utils.resources.pagination.types.meta_response import MetaResponse -from .annotation_queue import AnnotationQueue - - -class PaginatedAnnotationQueues(pydantic_v1.BaseModel): - data: typing.List[AnnotationQueue] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/annotation_queues/types/update_annotation_queue_item_request.py b/langfuse/api/resources/annotation_queues/types/update_annotation_queue_item_request.py deleted file mode 100644 index 3b1c130fe..000000000 --- a/langfuse/api/resources/annotation_queues/types/update_annotation_queue_item_request.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .annotation_queue_status import AnnotationQueueStatus - - -class UpdateAnnotationQueueItemRequest(pydantic_v1.BaseModel): - status: typing.Optional[AnnotationQueueStatus] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/blob_storage_integrations/__init__.py b/langfuse/api/resources/blob_storage_integrations/__init__.py deleted file mode 100644 index a635fba57..000000000 --- a/langfuse/api/resources/blob_storage_integrations/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - BlobStorageExportFrequency, - BlobStorageExportMode, - BlobStorageIntegrationDeletionResponse, - BlobStorageIntegrationFileType, - BlobStorageIntegrationResponse, - BlobStorageIntegrationType, - BlobStorageIntegrationsResponse, - CreateBlobStorageIntegrationRequest, -) - -__all__ = [ - "BlobStorageExportFrequency", - "BlobStorageExportMode", - "BlobStorageIntegrationDeletionResponse", - "BlobStorageIntegrationFileType", - "BlobStorageIntegrationResponse", - "BlobStorageIntegrationType", - "BlobStorageIntegrationsResponse", - "CreateBlobStorageIntegrationRequest", -] diff --git a/langfuse/api/resources/blob_storage_integrations/client.py b/langfuse/api/resources/blob_storage_integrations/client.py deleted file mode 100644 index 73aec4fa4..000000000 --- a/langfuse/api/resources/blob_storage_integrations/client.py +++ /dev/null @@ -1,492 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from .types.blob_storage_integration_deletion_response import ( - BlobStorageIntegrationDeletionResponse, -) -from .types.blob_storage_integration_response import BlobStorageIntegrationResponse -from .types.blob_storage_integrations_response import BlobStorageIntegrationsResponse -from .types.create_blob_storage_integration_request import ( - CreateBlobStorageIntegrationRequest, -) - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class BlobStorageIntegrationsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def get_blob_storage_integrations( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> BlobStorageIntegrationsResponse: - """ - Get all blob storage integrations for the organization (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - BlobStorageIntegrationsResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.blob_storage_integrations.get_blob_storage_integrations() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/integrations/blob-storage", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - BlobStorageIntegrationsResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def upsert_blob_storage_integration( - self, - *, - request: CreateBlobStorageIntegrationRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> BlobStorageIntegrationResponse: - """ - Create or update a blob storage integration for a specific project (requires organization-scoped API key). The configuration is validated by performing a test upload to the bucket. - - Parameters - ---------- - request : CreateBlobStorageIntegrationRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - BlobStorageIntegrationResponse - - Examples - -------- - from langfuse import ( - BlobStorageExportFrequency, - BlobStorageExportMode, - BlobStorageIntegrationFileType, - BlobStorageIntegrationType, - CreateBlobStorageIntegrationRequest, - ) - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.blob_storage_integrations.upsert_blob_storage_integration( - request=CreateBlobStorageIntegrationRequest( - project_id="projectId", - type=BlobStorageIntegrationType.S_3, - bucket_name="bucketName", - region="region", - export_frequency=BlobStorageExportFrequency.HOURLY, - enabled=True, - force_path_style=True, - file_type=BlobStorageIntegrationFileType.JSON, - export_mode=BlobStorageExportMode.FULL_HISTORY, - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/integrations/blob-storage", - method="PUT", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - BlobStorageIntegrationResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete_blob_storage_integration( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> BlobStorageIntegrationDeletionResponse: - """ - Delete a blob storage integration by ID (requires organization-scoped API key) - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - BlobStorageIntegrationDeletionResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.blob_storage_integrations.delete_blob_storage_integration( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/integrations/blob-storage/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - BlobStorageIntegrationDeletionResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncBlobStorageIntegrationsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def get_blob_storage_integrations( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> BlobStorageIntegrationsResponse: - """ - Get all blob storage integrations for the organization (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - BlobStorageIntegrationsResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.blob_storage_integrations.get_blob_storage_integrations() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/integrations/blob-storage", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - BlobStorageIntegrationsResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def upsert_blob_storage_integration( - self, - *, - request: CreateBlobStorageIntegrationRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> BlobStorageIntegrationResponse: - """ - Create or update a blob storage integration for a specific project (requires organization-scoped API key). The configuration is validated by performing a test upload to the bucket. - - Parameters - ---------- - request : CreateBlobStorageIntegrationRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - BlobStorageIntegrationResponse - - Examples - -------- - import asyncio - - from langfuse import ( - BlobStorageExportFrequency, - BlobStorageExportMode, - BlobStorageIntegrationFileType, - BlobStorageIntegrationType, - CreateBlobStorageIntegrationRequest, - ) - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.blob_storage_integrations.upsert_blob_storage_integration( - request=CreateBlobStorageIntegrationRequest( - project_id="projectId", - type=BlobStorageIntegrationType.S_3, - bucket_name="bucketName", - region="region", - export_frequency=BlobStorageExportFrequency.HOURLY, - enabled=True, - force_path_style=True, - file_type=BlobStorageIntegrationFileType.JSON, - export_mode=BlobStorageExportMode.FULL_HISTORY, - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/integrations/blob-storage", - method="PUT", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - BlobStorageIntegrationResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete_blob_storage_integration( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> BlobStorageIntegrationDeletionResponse: - """ - Delete a blob storage integration by ID (requires organization-scoped API key) - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - BlobStorageIntegrationDeletionResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.blob_storage_integrations.delete_blob_storage_integration( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/integrations/blob-storage/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - BlobStorageIntegrationDeletionResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/blob_storage_integrations/types/__init__.py b/langfuse/api/resources/blob_storage_integrations/types/__init__.py deleted file mode 100644 index 621196c11..000000000 --- a/langfuse/api/resources/blob_storage_integrations/types/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .blob_storage_export_frequency import BlobStorageExportFrequency -from .blob_storage_export_mode import BlobStorageExportMode -from .blob_storage_integration_deletion_response import ( - BlobStorageIntegrationDeletionResponse, -) -from .blob_storage_integration_file_type import BlobStorageIntegrationFileType -from .blob_storage_integration_response import BlobStorageIntegrationResponse -from .blob_storage_integration_type import BlobStorageIntegrationType -from .blob_storage_integrations_response import BlobStorageIntegrationsResponse -from .create_blob_storage_integration_request import CreateBlobStorageIntegrationRequest - -__all__ = [ - "BlobStorageExportFrequency", - "BlobStorageExportMode", - "BlobStorageIntegrationDeletionResponse", - "BlobStorageIntegrationFileType", - "BlobStorageIntegrationResponse", - "BlobStorageIntegrationType", - "BlobStorageIntegrationsResponse", - "CreateBlobStorageIntegrationRequest", -] diff --git a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_export_frequency.py b/langfuse/api/resources/blob_storage_integrations/types/blob_storage_export_frequency.py deleted file mode 100644 index 936e0c18f..000000000 --- a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_export_frequency.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class BlobStorageExportFrequency(str, enum.Enum): - HOURLY = "hourly" - DAILY = "daily" - WEEKLY = "weekly" - - def visit( - self, - hourly: typing.Callable[[], T_Result], - daily: typing.Callable[[], T_Result], - weekly: typing.Callable[[], T_Result], - ) -> T_Result: - if self is BlobStorageExportFrequency.HOURLY: - return hourly() - if self is BlobStorageExportFrequency.DAILY: - return daily() - if self is BlobStorageExportFrequency.WEEKLY: - return weekly() diff --git a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_export_mode.py b/langfuse/api/resources/blob_storage_integrations/types/blob_storage_export_mode.py deleted file mode 100644 index 1eafab79d..000000000 --- a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_export_mode.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class BlobStorageExportMode(str, enum.Enum): - FULL_HISTORY = "FULL_HISTORY" - FROM_TODAY = "FROM_TODAY" - FROM_CUSTOM_DATE = "FROM_CUSTOM_DATE" - - def visit( - self, - full_history: typing.Callable[[], T_Result], - from_today: typing.Callable[[], T_Result], - from_custom_date: typing.Callable[[], T_Result], - ) -> T_Result: - if self is BlobStorageExportMode.FULL_HISTORY: - return full_history() - if self is BlobStorageExportMode.FROM_TODAY: - return from_today() - if self is BlobStorageExportMode.FROM_CUSTOM_DATE: - return from_custom_date() diff --git a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_deletion_response.py b/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_deletion_response.py deleted file mode 100644 index 4305cff2f..000000000 --- a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_deletion_response.py +++ /dev/null @@ -1,42 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class BlobStorageIntegrationDeletionResponse(pydantic_v1.BaseModel): - message: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_file_type.py b/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_file_type.py deleted file mode 100644 index a63631c6f..000000000 --- a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_file_type.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class BlobStorageIntegrationFileType(str, enum.Enum): - JSON = "JSON" - CSV = "CSV" - JSONL = "JSONL" - - def visit( - self, - json: typing.Callable[[], T_Result], - csv: typing.Callable[[], T_Result], - jsonl: typing.Callable[[], T_Result], - ) -> T_Result: - if self is BlobStorageIntegrationFileType.JSON: - return json() - if self is BlobStorageIntegrationFileType.CSV: - return csv() - if self is BlobStorageIntegrationFileType.JSONL: - return jsonl() diff --git a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_response.py b/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_response.py deleted file mode 100644 index e308e8113..000000000 --- a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_response.py +++ /dev/null @@ -1,75 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .blob_storage_export_frequency import BlobStorageExportFrequency -from .blob_storage_export_mode import BlobStorageExportMode -from .blob_storage_integration_file_type import BlobStorageIntegrationFileType -from .blob_storage_integration_type import BlobStorageIntegrationType - - -class BlobStorageIntegrationResponse(pydantic_v1.BaseModel): - id: str - project_id: str = pydantic_v1.Field(alias="projectId") - type: BlobStorageIntegrationType - bucket_name: str = pydantic_v1.Field(alias="bucketName") - endpoint: typing.Optional[str] = None - region: str - access_key_id: typing.Optional[str] = pydantic_v1.Field( - alias="accessKeyId", default=None - ) - prefix: str - export_frequency: BlobStorageExportFrequency = pydantic_v1.Field( - alias="exportFrequency" - ) - enabled: bool - force_path_style: bool = pydantic_v1.Field(alias="forcePathStyle") - file_type: BlobStorageIntegrationFileType = pydantic_v1.Field(alias="fileType") - export_mode: BlobStorageExportMode = pydantic_v1.Field(alias="exportMode") - export_start_date: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="exportStartDate", default=None - ) - next_sync_at: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="nextSyncAt", default=None - ) - last_sync_at: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="lastSyncAt", default=None - ) - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_type.py b/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_type.py deleted file mode 100644 index 38bacbf85..000000000 --- a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integration_type.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class BlobStorageIntegrationType(str, enum.Enum): - S_3 = "S3" - S_3_COMPATIBLE = "S3_COMPATIBLE" - AZURE_BLOB_STORAGE = "AZURE_BLOB_STORAGE" - - def visit( - self, - s_3: typing.Callable[[], T_Result], - s_3_compatible: typing.Callable[[], T_Result], - azure_blob_storage: typing.Callable[[], T_Result], - ) -> T_Result: - if self is BlobStorageIntegrationType.S_3: - return s_3() - if self is BlobStorageIntegrationType.S_3_COMPATIBLE: - return s_3_compatible() - if self is BlobStorageIntegrationType.AZURE_BLOB_STORAGE: - return azure_blob_storage() diff --git a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integrations_response.py b/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integrations_response.py deleted file mode 100644 index c6231a23e..000000000 --- a/langfuse/api/resources/blob_storage_integrations/types/blob_storage_integrations_response.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .blob_storage_integration_response import BlobStorageIntegrationResponse - - -class BlobStorageIntegrationsResponse(pydantic_v1.BaseModel): - data: typing.List[BlobStorageIntegrationResponse] - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/blob_storage_integrations/types/create_blob_storage_integration_request.py b/langfuse/api/resources/blob_storage_integrations/types/create_blob_storage_integration_request.py deleted file mode 100644 index 31b5779c6..000000000 --- a/langfuse/api/resources/blob_storage_integrations/types/create_blob_storage_integration_request.py +++ /dev/null @@ -1,108 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .blob_storage_export_frequency import BlobStorageExportFrequency -from .blob_storage_export_mode import BlobStorageExportMode -from .blob_storage_integration_file_type import BlobStorageIntegrationFileType -from .blob_storage_integration_type import BlobStorageIntegrationType - - -class CreateBlobStorageIntegrationRequest(pydantic_v1.BaseModel): - project_id: str = pydantic_v1.Field(alias="projectId") - """ - ID of the project in which to configure the blob storage integration - """ - - type: BlobStorageIntegrationType - bucket_name: str = pydantic_v1.Field(alias="bucketName") - """ - Name of the storage bucket - """ - - endpoint: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - Custom endpoint URL (required for S3_COMPATIBLE type) - """ - - region: str = pydantic_v1.Field() - """ - Storage region - """ - - access_key_id: typing.Optional[str] = pydantic_v1.Field( - alias="accessKeyId", default=None - ) - """ - Access key ID for authentication - """ - - secret_access_key: typing.Optional[str] = pydantic_v1.Field( - alias="secretAccessKey", default=None - ) - """ - Secret access key for authentication (will be encrypted when stored) - """ - - prefix: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - Path prefix for exported files (must end with forward slash if provided) - """ - - export_frequency: BlobStorageExportFrequency = pydantic_v1.Field( - alias="exportFrequency" - ) - enabled: bool = pydantic_v1.Field() - """ - Whether the integration is active - """ - - force_path_style: bool = pydantic_v1.Field(alias="forcePathStyle") - """ - Use path-style URLs for S3 requests - """ - - file_type: BlobStorageIntegrationFileType = pydantic_v1.Field(alias="fileType") - export_mode: BlobStorageExportMode = pydantic_v1.Field(alias="exportMode") - export_start_date: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="exportStartDate", default=None - ) - """ - Custom start date for exports (required when exportMode is FROM_CUSTOM_DATE) - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/comments/__init__.py b/langfuse/api/resources/comments/__init__.py deleted file mode 100644 index e40c8546f..000000000 --- a/langfuse/api/resources/comments/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import CreateCommentRequest, CreateCommentResponse, GetCommentsResponse - -__all__ = ["CreateCommentRequest", "CreateCommentResponse", "GetCommentsResponse"] diff --git a/langfuse/api/resources/comments/client.py b/langfuse/api/resources/comments/client.py deleted file mode 100644 index 9c78ca23f..000000000 --- a/langfuse/api/resources/comments/client.py +++ /dev/null @@ -1,520 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from ..commons.types.comment import Comment -from .types.create_comment_request import CreateCommentRequest -from .types.create_comment_response import CreateCommentResponse -from .types.get_comments_response import GetCommentsResponse - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class CommentsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def create( - self, - *, - request: CreateCommentRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateCommentResponse: - """ - Create a comment. Comments may be attached to different object types (trace, observation, session, prompt). - - Parameters - ---------- - request : CreateCommentRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateCommentResponse - - Examples - -------- - from langfuse import CreateCommentRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.comments.create( - request=CreateCommentRequest( - project_id="projectId", - object_type="objectType", - object_id="objectId", - content="content", - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/comments", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(CreateCommentResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - object_type: typing.Optional[str] = None, - object_id: typing.Optional[str] = None, - author_user_id: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> GetCommentsResponse: - """ - Get all comments - - Parameters - ---------- - page : typing.Optional[int] - Page number, starts at 1. - - limit : typing.Optional[int] - Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit - - object_type : typing.Optional[str] - Filter comments by object type (trace, observation, session, prompt). - - object_id : typing.Optional[str] - Filter comments by object id. If objectType is not provided, an error will be thrown. - - author_user_id : typing.Optional[str] - Filter comments by author user id. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetCommentsResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.comments.get() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/comments", - method="GET", - params={ - "page": page, - "limit": limit, - "objectType": object_type, - "objectId": object_id, - "authorUserId": author_user_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(GetCommentsResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_by_id( - self, - comment_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> Comment: - """ - Get a comment by id - - Parameters - ---------- - comment_id : str - The unique langfuse identifier of a comment - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Comment - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.comments.get_by_id( - comment_id="commentId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/comments/{jsonable_encoder(comment_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncCommentsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def create( - self, - *, - request: CreateCommentRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateCommentResponse: - """ - Create a comment. Comments may be attached to different object types (trace, observation, session, prompt). - - Parameters - ---------- - request : CreateCommentRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateCommentResponse - - Examples - -------- - import asyncio - - from langfuse import CreateCommentRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.comments.create( - request=CreateCommentRequest( - project_id="projectId", - object_type="objectType", - object_id="objectId", - content="content", - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/comments", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(CreateCommentResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - object_type: typing.Optional[str] = None, - object_id: typing.Optional[str] = None, - author_user_id: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> GetCommentsResponse: - """ - Get all comments - - Parameters - ---------- - page : typing.Optional[int] - Page number, starts at 1. - - limit : typing.Optional[int] - Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit - - object_type : typing.Optional[str] - Filter comments by object type (trace, observation, session, prompt). - - object_id : typing.Optional[str] - Filter comments by object id. If objectType is not provided, an error will be thrown. - - author_user_id : typing.Optional[str] - Filter comments by author user id. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetCommentsResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.comments.get() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/comments", - method="GET", - params={ - "page": page, - "limit": limit, - "objectType": object_type, - "objectId": object_id, - "authorUserId": author_user_id, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(GetCommentsResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_by_id( - self, - comment_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> Comment: - """ - Get a comment by id - - Parameters - ---------- - comment_id : str - The unique langfuse identifier of a comment - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Comment - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.comments.get_by_id( - comment_id="commentId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/comments/{jsonable_encoder(comment_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Comment, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/comments/types/__init__.py b/langfuse/api/resources/comments/types/__init__.py deleted file mode 100644 index 13dc1d8d9..000000000 --- a/langfuse/api/resources/comments/types/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .create_comment_request import CreateCommentRequest -from .create_comment_response import CreateCommentResponse -from .get_comments_response import GetCommentsResponse - -__all__ = ["CreateCommentRequest", "CreateCommentResponse", "GetCommentsResponse"] diff --git a/langfuse/api/resources/comments/types/create_comment_request.py b/langfuse/api/resources/comments/types/create_comment_request.py deleted file mode 100644 index 3c35c64e2..000000000 --- a/langfuse/api/resources/comments/types/create_comment_request.py +++ /dev/null @@ -1,69 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class CreateCommentRequest(pydantic_v1.BaseModel): - project_id: str = pydantic_v1.Field(alias="projectId") - """ - The id of the project to attach the comment to. - """ - - object_type: str = pydantic_v1.Field(alias="objectType") - """ - The type of the object to attach the comment to (trace, observation, session, prompt). - """ - - object_id: str = pydantic_v1.Field(alias="objectId") - """ - The id of the object to attach the comment to. If this does not reference a valid existing object, an error will be thrown. - """ - - content: str = pydantic_v1.Field() - """ - The content of the comment. May include markdown. Currently limited to 5000 characters. - """ - - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - """ - The id of the user who created the comment. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/comments/types/create_comment_response.py b/langfuse/api/resources/comments/types/create_comment_response.py deleted file mode 100644 index d7708f798..000000000 --- a/langfuse/api/resources/comments/types/create_comment_response.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class CreateCommentResponse(pydantic_v1.BaseModel): - id: str = pydantic_v1.Field() - """ - The id of the created object in Langfuse - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/comments/types/get_comments_response.py b/langfuse/api/resources/comments/types/get_comments_response.py deleted file mode 100644 index 66a8b9527..000000000 --- a/langfuse/api/resources/comments/types/get_comments_response.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.comment import Comment -from ...utils.resources.pagination.types.meta_response import MetaResponse - - -class GetCommentsResponse(pydantic_v1.BaseModel): - data: typing.List[Comment] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/__init__.py b/langfuse/api/resources/commons/__init__.py deleted file mode 100644 index 77097ba49..000000000 --- a/langfuse/api/resources/commons/__init__.py +++ /dev/null @@ -1,111 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - BaseScore, - BaseScoreV1, - BooleanScore, - BooleanScoreV1, - CategoricalScore, - CategoricalScoreV1, - Comment, - CommentObjectType, - ConfigCategory, - CreateScoreValue, - Dataset, - DatasetItem, - DatasetRun, - DatasetRunItem, - DatasetRunWithItems, - DatasetStatus, - MapValue, - Model, - ModelPrice, - ModelUsageUnit, - NumericScore, - NumericScoreV1, - Observation, - ObservationLevel, - ObservationsView, - PricingTier, - PricingTierCondition, - PricingTierInput, - PricingTierOperator, - Score, - ScoreConfig, - ScoreDataType, - ScoreSource, - ScoreV1, - ScoreV1_Boolean, - ScoreV1_Categorical, - ScoreV1_Numeric, - Score_Boolean, - Score_Categorical, - Score_Numeric, - Session, - SessionWithTraces, - Trace, - TraceWithDetails, - TraceWithFullDetails, - Usage, -) -from .errors import ( - AccessDeniedError, - Error, - MethodNotAllowedError, - NotFoundError, - UnauthorizedError, -) - -__all__ = [ - "AccessDeniedError", - "BaseScore", - "BaseScoreV1", - "BooleanScore", - "BooleanScoreV1", - "CategoricalScore", - "CategoricalScoreV1", - "Comment", - "CommentObjectType", - "ConfigCategory", - "CreateScoreValue", - "Dataset", - "DatasetItem", - "DatasetRun", - "DatasetRunItem", - "DatasetRunWithItems", - "DatasetStatus", - "Error", - "MapValue", - "MethodNotAllowedError", - "Model", - "ModelPrice", - "ModelUsageUnit", - "NotFoundError", - "NumericScore", - "NumericScoreV1", - "Observation", - "ObservationLevel", - "ObservationsView", - "PricingTier", - "PricingTierCondition", - "PricingTierInput", - "PricingTierOperator", - "Score", - "ScoreConfig", - "ScoreDataType", - "ScoreSource", - "ScoreV1", - "ScoreV1_Boolean", - "ScoreV1_Categorical", - "ScoreV1_Numeric", - "Score_Boolean", - "Score_Categorical", - "Score_Numeric", - "Session", - "SessionWithTraces", - "Trace", - "TraceWithDetails", - "TraceWithFullDetails", - "UnauthorizedError", - "Usage", -] diff --git a/langfuse/api/resources/commons/errors/__init__.py b/langfuse/api/resources/commons/errors/__init__.py deleted file mode 100644 index 0aef2f92f..000000000 --- a/langfuse/api/resources/commons/errors/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .access_denied_error import AccessDeniedError -from .error import Error -from .method_not_allowed_error import MethodNotAllowedError -from .not_found_error import NotFoundError -from .unauthorized_error import UnauthorizedError - -__all__ = [ - "AccessDeniedError", - "Error", - "MethodNotAllowedError", - "NotFoundError", - "UnauthorizedError", -] diff --git a/langfuse/api/resources/commons/errors/access_denied_error.py b/langfuse/api/resources/commons/errors/access_denied_error.py deleted file mode 100644 index 9114ba9ac..000000000 --- a/langfuse/api/resources/commons/errors/access_denied_error.py +++ /dev/null @@ -1,10 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -from ....core.api_error import ApiError - - -class AccessDeniedError(ApiError): - def __init__(self, body: typing.Any): - super().__init__(status_code=403, body=body) diff --git a/langfuse/api/resources/commons/errors/error.py b/langfuse/api/resources/commons/errors/error.py deleted file mode 100644 index 06020120c..000000000 --- a/langfuse/api/resources/commons/errors/error.py +++ /dev/null @@ -1,10 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -from ....core.api_error import ApiError - - -class Error(ApiError): - def __init__(self, body: typing.Any): - super().__init__(status_code=400, body=body) diff --git a/langfuse/api/resources/commons/errors/method_not_allowed_error.py b/langfuse/api/resources/commons/errors/method_not_allowed_error.py deleted file mode 100644 index 32731a5c7..000000000 --- a/langfuse/api/resources/commons/errors/method_not_allowed_error.py +++ /dev/null @@ -1,10 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -from ....core.api_error import ApiError - - -class MethodNotAllowedError(ApiError): - def __init__(self, body: typing.Any): - super().__init__(status_code=405, body=body) diff --git a/langfuse/api/resources/commons/errors/not_found_error.py b/langfuse/api/resources/commons/errors/not_found_error.py deleted file mode 100644 index 564ffca2c..000000000 --- a/langfuse/api/resources/commons/errors/not_found_error.py +++ /dev/null @@ -1,10 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -from ....core.api_error import ApiError - - -class NotFoundError(ApiError): - def __init__(self, body: typing.Any): - super().__init__(status_code=404, body=body) diff --git a/langfuse/api/resources/commons/errors/unauthorized_error.py b/langfuse/api/resources/commons/errors/unauthorized_error.py deleted file mode 100644 index 2997f54f6..000000000 --- a/langfuse/api/resources/commons/errors/unauthorized_error.py +++ /dev/null @@ -1,10 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing - -from ....core.api_error import ApiError - - -class UnauthorizedError(ApiError): - def __init__(self, body: typing.Any): - super().__init__(status_code=401, body=body) diff --git a/langfuse/api/resources/commons/types/__init__.py b/langfuse/api/resources/commons/types/__init__.py deleted file mode 100644 index ee7f5714b..000000000 --- a/langfuse/api/resources/commons/types/__init__.py +++ /dev/null @@ -1,91 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .base_score import BaseScore -from .base_score_v_1 import BaseScoreV1 -from .boolean_score import BooleanScore -from .boolean_score_v_1 import BooleanScoreV1 -from .categorical_score import CategoricalScore -from .categorical_score_v_1 import CategoricalScoreV1 -from .comment import Comment -from .comment_object_type import CommentObjectType -from .config_category import ConfigCategory -from .create_score_value import CreateScoreValue -from .dataset import Dataset -from .dataset_item import DatasetItem -from .dataset_run import DatasetRun -from .dataset_run_item import DatasetRunItem -from .dataset_run_with_items import DatasetRunWithItems -from .dataset_status import DatasetStatus -from .map_value import MapValue -from .model import Model -from .model_price import ModelPrice -from .model_usage_unit import ModelUsageUnit -from .numeric_score import NumericScore -from .numeric_score_v_1 import NumericScoreV1 -from .observation import Observation -from .observation_level import ObservationLevel -from .observations_view import ObservationsView -from .pricing_tier import PricingTier -from .pricing_tier_condition import PricingTierCondition -from .pricing_tier_input import PricingTierInput -from .pricing_tier_operator import PricingTierOperator -from .score import Score, Score_Boolean, Score_Categorical, Score_Numeric -from .score_config import ScoreConfig -from .score_data_type import ScoreDataType -from .score_source import ScoreSource -from .score_v_1 import ScoreV1, ScoreV1_Boolean, ScoreV1_Categorical, ScoreV1_Numeric -from .session import Session -from .session_with_traces import SessionWithTraces -from .trace import Trace -from .trace_with_details import TraceWithDetails -from .trace_with_full_details import TraceWithFullDetails -from .usage import Usage - -__all__ = [ - "BaseScore", - "BaseScoreV1", - "BooleanScore", - "BooleanScoreV1", - "CategoricalScore", - "CategoricalScoreV1", - "Comment", - "CommentObjectType", - "ConfigCategory", - "CreateScoreValue", - "Dataset", - "DatasetItem", - "DatasetRun", - "DatasetRunItem", - "DatasetRunWithItems", - "DatasetStatus", - "MapValue", - "Model", - "ModelPrice", - "ModelUsageUnit", - "NumericScore", - "NumericScoreV1", - "Observation", - "ObservationLevel", - "ObservationsView", - "PricingTier", - "PricingTierCondition", - "PricingTierInput", - "PricingTierOperator", - "Score", - "ScoreConfig", - "ScoreDataType", - "ScoreSource", - "ScoreV1", - "ScoreV1_Boolean", - "ScoreV1_Categorical", - "ScoreV1_Numeric", - "Score_Boolean", - "Score_Categorical", - "Score_Numeric", - "Session", - "SessionWithTraces", - "Trace", - "TraceWithDetails", - "TraceWithFullDetails", - "Usage", -] diff --git a/langfuse/api/resources/commons/types/base_score.py b/langfuse/api/resources/commons/types/base_score.py deleted file mode 100644 index dd5449c83..000000000 --- a/langfuse/api/resources/commons/types/base_score.py +++ /dev/null @@ -1,79 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .score_source import ScoreSource - - -class BaseScore(pydantic_v1.BaseModel): - id: str - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - session_id: typing.Optional[str] = pydantic_v1.Field( - alias="sessionId", default=None - ) - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - dataset_run_id: typing.Optional[str] = pydantic_v1.Field( - alias="datasetRunId", default=None - ) - name: str - source: ScoreSource - timestamp: dt.datetime - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - """ - Reference a score config on a score. When set, config and score name must be equal and value must comply to optionally defined numerical range - """ - - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - """ - The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. - """ - - environment: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/base_score_v_1.py b/langfuse/api/resources/commons/types/base_score_v_1.py deleted file mode 100644 index 478dcc6e6..000000000 --- a/langfuse/api/resources/commons/types/base_score_v_1.py +++ /dev/null @@ -1,73 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .score_source import ScoreSource - - -class BaseScoreV1(pydantic_v1.BaseModel): - id: str - trace_id: str = pydantic_v1.Field(alias="traceId") - name: str - source: ScoreSource - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - timestamp: dt.datetime - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - """ - Reference a score config on a score. When set, config and score name must be equal and value must comply to optionally defined numerical range - """ - - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - """ - The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. - """ - - environment: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/boolean_score.py b/langfuse/api/resources/commons/types/boolean_score.py deleted file mode 100644 index d838b7db9..000000000 --- a/langfuse/api/resources/commons/types/boolean_score.py +++ /dev/null @@ -1,53 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_score import BaseScore - - -class BooleanScore(BaseScore): - value: float = pydantic_v1.Field() - """ - The numeric value of the score. Equals 1 for "True" and 0 for "False" - """ - - string_value: str = pydantic_v1.Field(alias="stringValue") - """ - The string representation of the score value. Is inferred from the numeric value and equals "True" or "False" - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/boolean_score_v_1.py b/langfuse/api/resources/commons/types/boolean_score_v_1.py deleted file mode 100644 index 9f8e8935f..000000000 --- a/langfuse/api/resources/commons/types/boolean_score_v_1.py +++ /dev/null @@ -1,53 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_score_v_1 import BaseScoreV1 - - -class BooleanScoreV1(BaseScoreV1): - value: float = pydantic_v1.Field() - """ - The numeric value of the score. Equals 1 for "True" and 0 for "False" - """ - - string_value: str = pydantic_v1.Field(alias="stringValue") - """ - The string representation of the score value. Is inferred from the numeric value and equals "True" or "False" - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/categorical_score.py b/langfuse/api/resources/commons/types/categorical_score.py deleted file mode 100644 index 363ed03ff..000000000 --- a/langfuse/api/resources/commons/types/categorical_score.py +++ /dev/null @@ -1,53 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_score import BaseScore - - -class CategoricalScore(BaseScore): - value: float = pydantic_v1.Field() - """ - Represents the numeric category mapping of the stringValue. If no config is linked, defaults to 0. - """ - - string_value: str = pydantic_v1.Field(alias="stringValue") - """ - The string representation of the score value. If no config is linked, can be any string. Otherwise, must map to a config category - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/categorical_score_v_1.py b/langfuse/api/resources/commons/types/categorical_score_v_1.py deleted file mode 100644 index 2aa42d586..000000000 --- a/langfuse/api/resources/commons/types/categorical_score_v_1.py +++ /dev/null @@ -1,53 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_score_v_1 import BaseScoreV1 - - -class CategoricalScoreV1(BaseScoreV1): - value: float = pydantic_v1.Field() - """ - Represents the numeric category mapping of the stringValue. If no config is linked, defaults to 0. - """ - - string_value: str = pydantic_v1.Field(alias="stringValue") - """ - The string representation of the score value. If no config is linked, can be any string. Otherwise, must map to a config category - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/comment.py b/langfuse/api/resources/commons/types/comment.py deleted file mode 100644 index 4d8b1916a..000000000 --- a/langfuse/api/resources/commons/types/comment.py +++ /dev/null @@ -1,54 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .comment_object_type import CommentObjectType - - -class Comment(pydantic_v1.BaseModel): - id: str - project_id: str = pydantic_v1.Field(alias="projectId") - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - object_type: CommentObjectType = pydantic_v1.Field(alias="objectType") - object_id: str = pydantic_v1.Field(alias="objectId") - content: str - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/comment_object_type.py b/langfuse/api/resources/commons/types/comment_object_type.py deleted file mode 100644 index 9c6c134c6..000000000 --- a/langfuse/api/resources/commons/types/comment_object_type.py +++ /dev/null @@ -1,29 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class CommentObjectType(str, enum.Enum): - TRACE = "TRACE" - OBSERVATION = "OBSERVATION" - SESSION = "SESSION" - PROMPT = "PROMPT" - - def visit( - self, - trace: typing.Callable[[], T_Result], - observation: typing.Callable[[], T_Result], - session: typing.Callable[[], T_Result], - prompt: typing.Callable[[], T_Result], - ) -> T_Result: - if self is CommentObjectType.TRACE: - return trace() - if self is CommentObjectType.OBSERVATION: - return observation() - if self is CommentObjectType.SESSION: - return session() - if self is CommentObjectType.PROMPT: - return prompt() diff --git a/langfuse/api/resources/commons/types/config_category.py b/langfuse/api/resources/commons/types/config_category.py deleted file mode 100644 index b1cbde9f2..000000000 --- a/langfuse/api/resources/commons/types/config_category.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ConfigCategory(pydantic_v1.BaseModel): - value: float - label: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/dataset.py b/langfuse/api/resources/commons/types/dataset.py deleted file mode 100644 index 116bff135..000000000 --- a/langfuse/api/resources/commons/types/dataset.py +++ /dev/null @@ -1,64 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class Dataset(pydantic_v1.BaseModel): - id: str - name: str - description: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - input_schema: typing.Optional[typing.Any] = pydantic_v1.Field( - alias="inputSchema", default=None - ) - """ - JSON Schema for validating dataset item inputs - """ - - expected_output_schema: typing.Optional[typing.Any] = pydantic_v1.Field( - alias="expectedOutputSchema", default=None - ) - """ - JSON Schema for validating dataset item expected outputs - """ - - project_id: str = pydantic_v1.Field(alias="projectId") - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/dataset_item.py b/langfuse/api/resources/commons/types/dataset_item.py deleted file mode 100644 index dd5f85e78..000000000 --- a/langfuse/api/resources/commons/types/dataset_item.py +++ /dev/null @@ -1,61 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .dataset_status import DatasetStatus - - -class DatasetItem(pydantic_v1.BaseModel): - id: str - status: DatasetStatus - input: typing.Optional[typing.Any] = None - expected_output: typing.Optional[typing.Any] = pydantic_v1.Field( - alias="expectedOutput", default=None - ) - metadata: typing.Optional[typing.Any] = None - source_trace_id: typing.Optional[str] = pydantic_v1.Field( - alias="sourceTraceId", default=None - ) - source_observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="sourceObservationId", default=None - ) - dataset_id: str = pydantic_v1.Field(alias="datasetId") - dataset_name: str = pydantic_v1.Field(alias="datasetName") - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/dataset_run.py b/langfuse/api/resources/commons/types/dataset_run.py deleted file mode 100644 index 74b1a2ac8..000000000 --- a/langfuse/api/resources/commons/types/dataset_run.py +++ /dev/null @@ -1,82 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class DatasetRun(pydantic_v1.BaseModel): - id: str = pydantic_v1.Field() - """ - Unique identifier of the dataset run - """ - - name: str = pydantic_v1.Field() - """ - Name of the dataset run - """ - - description: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - Description of the run - """ - - metadata: typing.Optional[typing.Any] = pydantic_v1.Field(default=None) - """ - Metadata of the dataset run - """ - - dataset_id: str = pydantic_v1.Field(alias="datasetId") - """ - Id of the associated dataset - """ - - dataset_name: str = pydantic_v1.Field(alias="datasetName") - """ - Name of the associated dataset - """ - - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - """ - The date and time when the dataset run was created - """ - - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - """ - The date and time when the dataset run was last updated - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/dataset_run_item.py b/langfuse/api/resources/commons/types/dataset_run_item.py deleted file mode 100644 index f1b3af163..000000000 --- a/langfuse/api/resources/commons/types/dataset_run_item.py +++ /dev/null @@ -1,53 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class DatasetRunItem(pydantic_v1.BaseModel): - id: str - dataset_run_id: str = pydantic_v1.Field(alias="datasetRunId") - dataset_run_name: str = pydantic_v1.Field(alias="datasetRunName") - dataset_item_id: str = pydantic_v1.Field(alias="datasetItemId") - trace_id: str = pydantic_v1.Field(alias="traceId") - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/dataset_run_with_items.py b/langfuse/api/resources/commons/types/dataset_run_with_items.py deleted file mode 100644 index 647d2c553..000000000 --- a/langfuse/api/resources/commons/types/dataset_run_with_items.py +++ /dev/null @@ -1,48 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .dataset_run import DatasetRun -from .dataset_run_item import DatasetRunItem - - -class DatasetRunWithItems(DatasetRun): - dataset_run_items: typing.List[DatasetRunItem] = pydantic_v1.Field( - alias="datasetRunItems" - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/dataset_status.py b/langfuse/api/resources/commons/types/dataset_status.py deleted file mode 100644 index 09eac62fe..000000000 --- a/langfuse/api/resources/commons/types/dataset_status.py +++ /dev/null @@ -1,21 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class DatasetStatus(str, enum.Enum): - ACTIVE = "ACTIVE" - ARCHIVED = "ARCHIVED" - - def visit( - self, - active: typing.Callable[[], T_Result], - archived: typing.Callable[[], T_Result], - ) -> T_Result: - if self is DatasetStatus.ACTIVE: - return active() - if self is DatasetStatus.ARCHIVED: - return archived() diff --git a/langfuse/api/resources/commons/types/model_price.py b/langfuse/api/resources/commons/types/model_price.py deleted file mode 100644 index 8882004e7..000000000 --- a/langfuse/api/resources/commons/types/model_price.py +++ /dev/null @@ -1,42 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ModelPrice(pydantic_v1.BaseModel): - price: float - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/model_usage_unit.py b/langfuse/api/resources/commons/types/model_usage_unit.py deleted file mode 100644 index 35253f92e..000000000 --- a/langfuse/api/resources/commons/types/model_usage_unit.py +++ /dev/null @@ -1,41 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class ModelUsageUnit(str, enum.Enum): - """ - Unit of usage in Langfuse - """ - - CHARACTERS = "CHARACTERS" - TOKENS = "TOKENS" - MILLISECONDS = "MILLISECONDS" - SECONDS = "SECONDS" - IMAGES = "IMAGES" - REQUESTS = "REQUESTS" - - def visit( - self, - characters: typing.Callable[[], T_Result], - tokens: typing.Callable[[], T_Result], - milliseconds: typing.Callable[[], T_Result], - seconds: typing.Callable[[], T_Result], - images: typing.Callable[[], T_Result], - requests: typing.Callable[[], T_Result], - ) -> T_Result: - if self is ModelUsageUnit.CHARACTERS: - return characters() - if self is ModelUsageUnit.TOKENS: - return tokens() - if self is ModelUsageUnit.MILLISECONDS: - return milliseconds() - if self is ModelUsageUnit.SECONDS: - return seconds() - if self is ModelUsageUnit.IMAGES: - return images() - if self is ModelUsageUnit.REQUESTS: - return requests() diff --git a/langfuse/api/resources/commons/types/numeric_score.py b/langfuse/api/resources/commons/types/numeric_score.py deleted file mode 100644 index d7f860cd5..000000000 --- a/langfuse/api/resources/commons/types/numeric_score.py +++ /dev/null @@ -1,48 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_score import BaseScore - - -class NumericScore(BaseScore): - value: float = pydantic_v1.Field() - """ - The numeric value of the score - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/numeric_score_v_1.py b/langfuse/api/resources/commons/types/numeric_score_v_1.py deleted file mode 100644 index 773d84b46..000000000 --- a/langfuse/api/resources/commons/types/numeric_score_v_1.py +++ /dev/null @@ -1,48 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_score_v_1 import BaseScoreV1 - - -class NumericScoreV1(BaseScoreV1): - value: float = pydantic_v1.Field() - """ - The numeric value of the score - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/observation.py b/langfuse/api/resources/commons/types/observation.py deleted file mode 100644 index b821476f9..000000000 --- a/langfuse/api/resources/commons/types/observation.py +++ /dev/null @@ -1,164 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .map_value import MapValue -from .observation_level import ObservationLevel -from .usage import Usage - - -class Observation(pydantic_v1.BaseModel): - id: str = pydantic_v1.Field() - """ - The unique identifier of the observation - """ - - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - """ - The trace ID associated with the observation - """ - - type: str = pydantic_v1.Field() - """ - The type of the observation - """ - - name: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The name of the observation - """ - - start_time: dt.datetime = pydantic_v1.Field(alias="startTime") - """ - The start time of the observation - """ - - end_time: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="endTime", default=None - ) - """ - The end time of the observation. - """ - - completion_start_time: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="completionStartTime", default=None - ) - """ - The completion start time of the observation - """ - - model: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The model used for the observation - """ - - model_parameters: typing.Optional[typing.Dict[str, MapValue]] = pydantic_v1.Field( - alias="modelParameters", default=None - ) - """ - The parameters of the model used for the observation - """ - - input: typing.Optional[typing.Any] = pydantic_v1.Field(default=None) - """ - The input data of the observation - """ - - version: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The version of the observation - """ - - metadata: typing.Optional[typing.Any] = pydantic_v1.Field(default=None) - """ - Additional metadata of the observation - """ - - output: typing.Optional[typing.Any] = pydantic_v1.Field(default=None) - """ - The output data of the observation - """ - - usage: typing.Optional[Usage] = pydantic_v1.Field(default=None) - """ - (Deprecated. Use usageDetails and costDetails instead.) The usage data of the observation - """ - - level: ObservationLevel = pydantic_v1.Field() - """ - The level of the observation - """ - - status_message: typing.Optional[str] = pydantic_v1.Field( - alias="statusMessage", default=None - ) - """ - The status message of the observation - """ - - parent_observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="parentObservationId", default=None - ) - """ - The parent observation ID - """ - - prompt_id: typing.Optional[str] = pydantic_v1.Field(alias="promptId", default=None) - """ - The prompt ID associated with the observation - """ - - usage_details: typing.Optional[typing.Dict[str, int]] = pydantic_v1.Field( - alias="usageDetails", default=None - ) - """ - The usage details of the observation. Key is the name of the usage metric, value is the number of units consumed. The total key is the sum of all (non-total) usage metrics or the total value ingested. - """ - - cost_details: typing.Optional[typing.Dict[str, float]] = pydantic_v1.Field( - alias="costDetails", default=None - ) - """ - The cost details of the observation. Key is the name of the cost metric, value is the cost in USD. The total key is the sum of all (non-total) cost metrics or the total value ingested. - """ - - environment: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The environment from which this observation originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/observation_level.py b/langfuse/api/resources/commons/types/observation_level.py deleted file mode 100644 index c33e87b59..000000000 --- a/langfuse/api/resources/commons/types/observation_level.py +++ /dev/null @@ -1,29 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class ObservationLevel(str, enum.Enum): - DEBUG = "DEBUG" - DEFAULT = "DEFAULT" - WARNING = "WARNING" - ERROR = "ERROR" - - def visit( - self, - debug: typing.Callable[[], T_Result], - default: typing.Callable[[], T_Result], - warning: typing.Callable[[], T_Result], - error: typing.Callable[[], T_Result], - ) -> T_Result: - if self is ObservationLevel.DEBUG: - return debug() - if self is ObservationLevel.DEFAULT: - return default() - if self is ObservationLevel.WARNING: - return warning() - if self is ObservationLevel.ERROR: - return error() diff --git a/langfuse/api/resources/commons/types/observations_view.py b/langfuse/api/resources/commons/types/observations_view.py deleted file mode 100644 index e011fa32b..000000000 --- a/langfuse/api/resources/commons/types/observations_view.py +++ /dev/null @@ -1,116 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .observation import Observation - - -class ObservationsView(Observation): - prompt_name: typing.Optional[str] = pydantic_v1.Field( - alias="promptName", default=None - ) - """ - The name of the prompt associated with the observation - """ - - prompt_version: typing.Optional[int] = pydantic_v1.Field( - alias="promptVersion", default=None - ) - """ - The version of the prompt associated with the observation - """ - - model_id: typing.Optional[str] = pydantic_v1.Field(alias="modelId", default=None) - """ - The unique identifier of the model - """ - - input_price: typing.Optional[float] = pydantic_v1.Field( - alias="inputPrice", default=None - ) - """ - The price of the input in USD - """ - - output_price: typing.Optional[float] = pydantic_v1.Field( - alias="outputPrice", default=None - ) - """ - The price of the output in USD. - """ - - total_price: typing.Optional[float] = pydantic_v1.Field( - alias="totalPrice", default=None - ) - """ - The total price in USD. - """ - - calculated_input_cost: typing.Optional[float] = pydantic_v1.Field( - alias="calculatedInputCost", default=None - ) - """ - (Deprecated. Use usageDetails and costDetails instead.) The calculated cost of the input in USD - """ - - calculated_output_cost: typing.Optional[float] = pydantic_v1.Field( - alias="calculatedOutputCost", default=None - ) - """ - (Deprecated. Use usageDetails and costDetails instead.) The calculated cost of the output in USD - """ - - calculated_total_cost: typing.Optional[float] = pydantic_v1.Field( - alias="calculatedTotalCost", default=None - ) - """ - (Deprecated. Use usageDetails and costDetails instead.) The calculated total cost in USD - """ - - latency: typing.Optional[float] = pydantic_v1.Field(default=None) - """ - The latency in seconds. - """ - - time_to_first_token: typing.Optional[float] = pydantic_v1.Field( - alias="timeToFirstToken", default=None - ) - """ - The time to the first token in seconds - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/pricing_tier_operator.py b/langfuse/api/resources/commons/types/pricing_tier_operator.py deleted file mode 100644 index c5af10199..000000000 --- a/langfuse/api/resources/commons/types/pricing_tier_operator.py +++ /dev/null @@ -1,41 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class PricingTierOperator(str, enum.Enum): - """ - Comparison operators for pricing tier conditions - """ - - GT = "gt" - GTE = "gte" - LT = "lt" - LTE = "lte" - EQ = "eq" - NEQ = "neq" - - def visit( - self, - gt: typing.Callable[[], T_Result], - gte: typing.Callable[[], T_Result], - lt: typing.Callable[[], T_Result], - lte: typing.Callable[[], T_Result], - eq: typing.Callable[[], T_Result], - neq: typing.Callable[[], T_Result], - ) -> T_Result: - if self is PricingTierOperator.GT: - return gt() - if self is PricingTierOperator.GTE: - return gte() - if self is PricingTierOperator.LT: - return lt() - if self is PricingTierOperator.LTE: - return lte() - if self is PricingTierOperator.EQ: - return eq() - if self is PricingTierOperator.NEQ: - return neq() diff --git a/langfuse/api/resources/commons/types/score.py b/langfuse/api/resources/commons/types/score.py deleted file mode 100644 index f0b866067..000000000 --- a/langfuse/api/resources/commons/types/score.py +++ /dev/null @@ -1,207 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from __future__ import annotations - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .score_source import ScoreSource - - -class Score_Numeric(pydantic_v1.BaseModel): - value: float - id: str - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - session_id: typing.Optional[str] = pydantic_v1.Field( - alias="sessionId", default=None - ) - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - dataset_run_id: typing.Optional[str] = pydantic_v1.Field( - alias="datasetRunId", default=None - ) - name: str - source: ScoreSource - timestamp: dt.datetime - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - environment: typing.Optional[str] = None - data_type: typing.Literal["NUMERIC"] = pydantic_v1.Field( - alias="dataType", default="NUMERIC" - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class Score_Categorical(pydantic_v1.BaseModel): - value: float - string_value: str = pydantic_v1.Field(alias="stringValue") - id: str - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - session_id: typing.Optional[str] = pydantic_v1.Field( - alias="sessionId", default=None - ) - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - dataset_run_id: typing.Optional[str] = pydantic_v1.Field( - alias="datasetRunId", default=None - ) - name: str - source: ScoreSource - timestamp: dt.datetime - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - environment: typing.Optional[str] = None - data_type: typing.Literal["CATEGORICAL"] = pydantic_v1.Field( - alias="dataType", default="CATEGORICAL" - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class Score_Boolean(pydantic_v1.BaseModel): - value: float - string_value: str = pydantic_v1.Field(alias="stringValue") - id: str - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - session_id: typing.Optional[str] = pydantic_v1.Field( - alias="sessionId", default=None - ) - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - dataset_run_id: typing.Optional[str] = pydantic_v1.Field( - alias="datasetRunId", default=None - ) - name: str - source: ScoreSource - timestamp: dt.datetime - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - environment: typing.Optional[str] = None - data_type: typing.Literal["BOOLEAN"] = pydantic_v1.Field( - alias="dataType", default="BOOLEAN" - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -Score = typing.Union[Score_Numeric, Score_Categorical, Score_Boolean] diff --git a/langfuse/api/resources/commons/types/score_config.py b/langfuse/api/resources/commons/types/score_config.py deleted file mode 100644 index 4a7b30e0e..000000000 --- a/langfuse/api/resources/commons/types/score_config.py +++ /dev/null @@ -1,82 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .config_category import ConfigCategory -from .score_data_type import ScoreDataType - - -class ScoreConfig(pydantic_v1.BaseModel): - """ - Configuration for a score - """ - - id: str - name: str - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - project_id: str = pydantic_v1.Field(alias="projectId") - data_type: ScoreDataType = pydantic_v1.Field(alias="dataType") - is_archived: bool = pydantic_v1.Field(alias="isArchived") - """ - Whether the score config is archived. Defaults to false - """ - - min_value: typing.Optional[float] = pydantic_v1.Field( - alias="minValue", default=None - ) - """ - Sets minimum value for numerical scores. If not set, the minimum value defaults to -∞ - """ - - max_value: typing.Optional[float] = pydantic_v1.Field( - alias="maxValue", default=None - ) - """ - Sets maximum value for numerical scores. If not set, the maximum value defaults to +∞ - """ - - categories: typing.Optional[typing.List[ConfigCategory]] = pydantic_v1.Field( - default=None - ) - """ - Configures custom categories for categorical scores - """ - - description: typing.Optional[str] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/score_data_type.py b/langfuse/api/resources/commons/types/score_data_type.py deleted file mode 100644 index c2eed12cd..000000000 --- a/langfuse/api/resources/commons/types/score_data_type.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class ScoreDataType(str, enum.Enum): - NUMERIC = "NUMERIC" - BOOLEAN = "BOOLEAN" - CATEGORICAL = "CATEGORICAL" - - def visit( - self, - numeric: typing.Callable[[], T_Result], - boolean: typing.Callable[[], T_Result], - categorical: typing.Callable[[], T_Result], - ) -> T_Result: - if self is ScoreDataType.NUMERIC: - return numeric() - if self is ScoreDataType.BOOLEAN: - return boolean() - if self is ScoreDataType.CATEGORICAL: - return categorical() diff --git a/langfuse/api/resources/commons/types/score_source.py b/langfuse/api/resources/commons/types/score_source.py deleted file mode 100644 index 699f078b7..000000000 --- a/langfuse/api/resources/commons/types/score_source.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class ScoreSource(str, enum.Enum): - ANNOTATION = "ANNOTATION" - API = "API" - EVAL = "EVAL" - - def visit( - self, - annotation: typing.Callable[[], T_Result], - api: typing.Callable[[], T_Result], - eval: typing.Callable[[], T_Result], - ) -> T_Result: - if self is ScoreSource.ANNOTATION: - return annotation() - if self is ScoreSource.API: - return api() - if self is ScoreSource.EVAL: - return eval() diff --git a/langfuse/api/resources/commons/types/score_v_1.py b/langfuse/api/resources/commons/types/score_v_1.py deleted file mode 100644 index 191e0d96f..000000000 --- a/langfuse/api/resources/commons/types/score_v_1.py +++ /dev/null @@ -1,189 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from __future__ import annotations - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .score_source import ScoreSource - - -class ScoreV1_Numeric(pydantic_v1.BaseModel): - value: float - id: str - trace_id: str = pydantic_v1.Field(alias="traceId") - name: str - source: ScoreSource - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - timestamp: dt.datetime - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - environment: typing.Optional[str] = None - data_type: typing.Literal["NUMERIC"] = pydantic_v1.Field( - alias="dataType", default="NUMERIC" - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class ScoreV1_Categorical(pydantic_v1.BaseModel): - value: float - string_value: str = pydantic_v1.Field(alias="stringValue") - id: str - trace_id: str = pydantic_v1.Field(alias="traceId") - name: str - source: ScoreSource - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - timestamp: dt.datetime - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - environment: typing.Optional[str] = None - data_type: typing.Literal["CATEGORICAL"] = pydantic_v1.Field( - alias="dataType", default="CATEGORICAL" - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class ScoreV1_Boolean(pydantic_v1.BaseModel): - value: float - string_value: str = pydantic_v1.Field(alias="stringValue") - id: str - trace_id: str = pydantic_v1.Field(alias="traceId") - name: str - source: ScoreSource - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - timestamp: dt.datetime - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - environment: typing.Optional[str] = None - data_type: typing.Literal["BOOLEAN"] = pydantic_v1.Field( - alias="dataType", default="BOOLEAN" - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -ScoreV1 = typing.Union[ScoreV1_Numeric, ScoreV1_Categorical, ScoreV1_Boolean] diff --git a/langfuse/api/resources/commons/types/session.py b/langfuse/api/resources/commons/types/session.py deleted file mode 100644 index 46a0a6b96..000000000 --- a/langfuse/api/resources/commons/types/session.py +++ /dev/null @@ -1,50 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class Session(pydantic_v1.BaseModel): - id: str - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - project_id: str = pydantic_v1.Field(alias="projectId") - environment: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The environment from which this session originated. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/session_with_traces.py b/langfuse/api/resources/commons/types/session_with_traces.py deleted file mode 100644 index b5465daa9..000000000 --- a/langfuse/api/resources/commons/types/session_with_traces.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .session import Session -from .trace import Trace - - -class SessionWithTraces(Session): - traces: typing.List[Trace] - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/trace.py b/langfuse/api/resources/commons/types/trace.py deleted file mode 100644 index d977ed3d7..000000000 --- a/langfuse/api/resources/commons/types/trace.py +++ /dev/null @@ -1,109 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class Trace(pydantic_v1.BaseModel): - id: str = pydantic_v1.Field() - """ - The unique identifier of a trace - """ - - timestamp: dt.datetime = pydantic_v1.Field() - """ - The timestamp when the trace was created - """ - - name: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The name of the trace - """ - - input: typing.Optional[typing.Any] = pydantic_v1.Field(default=None) - """ - The input data of the trace. Can be any JSON. - """ - - output: typing.Optional[typing.Any] = pydantic_v1.Field(default=None) - """ - The output data of the trace. Can be any JSON. - """ - - session_id: typing.Optional[str] = pydantic_v1.Field( - alias="sessionId", default=None - ) - """ - The session identifier associated with the trace - """ - - release: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The release version of the application when the trace was created - """ - - version: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The version of the trace - """ - - user_id: typing.Optional[str] = pydantic_v1.Field(alias="userId", default=None) - """ - The user identifier associated with the trace - """ - - metadata: typing.Optional[typing.Any] = pydantic_v1.Field(default=None) - """ - The metadata associated with the trace. Can be any JSON. - """ - - tags: typing.Optional[typing.List[str]] = pydantic_v1.Field(default=None) - """ - The tags associated with the trace. Can be an array of strings or null. - """ - - public: typing.Optional[bool] = pydantic_v1.Field(default=None) - """ - Public traces are accessible via url without login - """ - - environment: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The environment from which this trace originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/trace_with_details.py b/langfuse/api/resources/commons/types/trace_with_details.py deleted file mode 100644 index 5ffe6f218..000000000 --- a/langfuse/api/resources/commons/types/trace_with_details.py +++ /dev/null @@ -1,68 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .trace import Trace - - -class TraceWithDetails(Trace): - html_path: str = pydantic_v1.Field(alias="htmlPath") - """ - Path of trace in Langfuse UI - """ - - latency: float = pydantic_v1.Field() - """ - Latency of trace in seconds - """ - - total_cost: float = pydantic_v1.Field(alias="totalCost") - """ - Cost of trace in USD - """ - - observations: typing.List[str] = pydantic_v1.Field() - """ - List of observation ids - """ - - scores: typing.List[str] = pydantic_v1.Field() - """ - List of score ids - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/trace_with_full_details.py b/langfuse/api/resources/commons/types/trace_with_full_details.py deleted file mode 100644 index 2c6a99402..000000000 --- a/langfuse/api/resources/commons/types/trace_with_full_details.py +++ /dev/null @@ -1,70 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .observations_view import ObservationsView -from .score_v_1 import ScoreV1 -from .trace import Trace - - -class TraceWithFullDetails(Trace): - html_path: str = pydantic_v1.Field(alias="htmlPath") - """ - Path of trace in Langfuse UI - """ - - latency: float = pydantic_v1.Field() - """ - Latency of trace in seconds - """ - - total_cost: float = pydantic_v1.Field(alias="totalCost") - """ - Cost of trace in USD - """ - - observations: typing.List[ObservationsView] = pydantic_v1.Field() - """ - List of observations - """ - - scores: typing.List[ScoreV1] = pydantic_v1.Field() - """ - List of scores - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/commons/types/usage.py b/langfuse/api/resources/commons/types/usage.py deleted file mode 100644 index c38330494..000000000 --- a/langfuse/api/resources/commons/types/usage.py +++ /dev/null @@ -1,84 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .model_usage_unit import ModelUsageUnit - - -class Usage(pydantic_v1.BaseModel): - """ - (Deprecated. Use usageDetails and costDetails instead.) Standard interface for usage and cost - """ - - input: typing.Optional[int] = pydantic_v1.Field(default=None) - """ - Number of input units (e.g. tokens) - """ - - output: typing.Optional[int] = pydantic_v1.Field(default=None) - """ - Number of output units (e.g. tokens) - """ - - total: typing.Optional[int] = pydantic_v1.Field(default=None) - """ - Defaults to input+output if not set - """ - - unit: typing.Optional[ModelUsageUnit] = None - input_cost: typing.Optional[float] = pydantic_v1.Field( - alias="inputCost", default=None - ) - """ - USD input cost - """ - - output_cost: typing.Optional[float] = pydantic_v1.Field( - alias="outputCost", default=None - ) - """ - USD output cost - """ - - total_cost: typing.Optional[float] = pydantic_v1.Field( - alias="totalCost", default=None - ) - """ - USD total cost, defaults to input+output - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/dataset_items/__init__.py b/langfuse/api/resources/dataset_items/__init__.py deleted file mode 100644 index 06d2ae527..000000000 --- a/langfuse/api/resources/dataset_items/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - CreateDatasetItemRequest, - DeleteDatasetItemResponse, - PaginatedDatasetItems, -) - -__all__ = [ - "CreateDatasetItemRequest", - "DeleteDatasetItemResponse", - "PaginatedDatasetItems", -] diff --git a/langfuse/api/resources/dataset_items/client.py b/langfuse/api/resources/dataset_items/client.py deleted file mode 100644 index 8ece3a790..000000000 --- a/langfuse/api/resources/dataset_items/client.py +++ /dev/null @@ -1,640 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from ..commons.types.dataset_item import DatasetItem -from .types.create_dataset_item_request import CreateDatasetItemRequest -from .types.delete_dataset_item_response import DeleteDatasetItemResponse -from .types.paginated_dataset_items import PaginatedDatasetItems - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class DatasetItemsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def create( - self, - *, - request: CreateDatasetItemRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> DatasetItem: - """ - Create a dataset item - - Parameters - ---------- - request : CreateDatasetItemRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DatasetItem - - Examples - -------- - from langfuse import CreateDatasetItemRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.dataset_items.create( - request=CreateDatasetItemRequest( - dataset_name="datasetName", - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/dataset-items", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DatasetItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> DatasetItem: - """ - Get a dataset item - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DatasetItem - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.dataset_items.get( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/dataset-items/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DatasetItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list( - self, - *, - dataset_name: typing.Optional[str] = None, - source_trace_id: typing.Optional[str] = None, - source_observation_id: typing.Optional[str] = None, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedDatasetItems: - """ - Get dataset items - - Parameters - ---------- - dataset_name : typing.Optional[str] - - source_trace_id : typing.Optional[str] - - source_observation_id : typing.Optional[str] - - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedDatasetItems - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.dataset_items.list() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/dataset-items", - method="GET", - params={ - "datasetName": dataset_name, - "sourceTraceId": source_trace_id, - "sourceObservationId": source_observation_id, - "page": page, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(PaginatedDatasetItems, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> DeleteDatasetItemResponse: - """ - Delete a dataset item and all its run items. This action is irreversible. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteDatasetItemResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.dataset_items.delete( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/dataset-items/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - DeleteDatasetItemResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncDatasetItemsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def create( - self, - *, - request: CreateDatasetItemRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> DatasetItem: - """ - Create a dataset item - - Parameters - ---------- - request : CreateDatasetItemRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DatasetItem - - Examples - -------- - import asyncio - - from langfuse import CreateDatasetItemRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.dataset_items.create( - request=CreateDatasetItemRequest( - dataset_name="datasetName", - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/dataset-items", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DatasetItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> DatasetItem: - """ - Get a dataset item - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DatasetItem - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.dataset_items.get( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/dataset-items/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DatasetItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list( - self, - *, - dataset_name: typing.Optional[str] = None, - source_trace_id: typing.Optional[str] = None, - source_observation_id: typing.Optional[str] = None, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedDatasetItems: - """ - Get dataset items - - Parameters - ---------- - dataset_name : typing.Optional[str] - - source_trace_id : typing.Optional[str] - - source_observation_id : typing.Optional[str] - - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedDatasetItems - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.dataset_items.list() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/dataset-items", - method="GET", - params={ - "datasetName": dataset_name, - "sourceTraceId": source_trace_id, - "sourceObservationId": source_observation_id, - "page": page, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(PaginatedDatasetItems, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> DeleteDatasetItemResponse: - """ - Delete a dataset item and all its run items. This action is irreversible. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteDatasetItemResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.dataset_items.delete( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/dataset-items/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - DeleteDatasetItemResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/dataset_items/types/__init__.py b/langfuse/api/resources/dataset_items/types/__init__.py deleted file mode 100644 index 214adce0e..000000000 --- a/langfuse/api/resources/dataset_items/types/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .create_dataset_item_request import CreateDatasetItemRequest -from .delete_dataset_item_response import DeleteDatasetItemResponse -from .paginated_dataset_items import PaginatedDatasetItems - -__all__ = [ - "CreateDatasetItemRequest", - "DeleteDatasetItemResponse", - "PaginatedDatasetItems", -] diff --git a/langfuse/api/resources/dataset_items/types/create_dataset_item_request.py b/langfuse/api/resources/dataset_items/types/create_dataset_item_request.py deleted file mode 100644 index 111f6819a..000000000 --- a/langfuse/api/resources/dataset_items/types/create_dataset_item_request.py +++ /dev/null @@ -1,65 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.dataset_status import DatasetStatus - - -class CreateDatasetItemRequest(pydantic_v1.BaseModel): - dataset_name: str = pydantic_v1.Field(alias="datasetName") - input: typing.Optional[typing.Any] = None - expected_output: typing.Optional[typing.Any] = pydantic_v1.Field( - alias="expectedOutput", default=None - ) - metadata: typing.Optional[typing.Any] = None - source_trace_id: typing.Optional[str] = pydantic_v1.Field( - alias="sourceTraceId", default=None - ) - source_observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="sourceObservationId", default=None - ) - id: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - Dataset items are upserted on their id. Id needs to be unique (project-level) and cannot be reused across datasets. - """ - - status: typing.Optional[DatasetStatus] = pydantic_v1.Field(default=None) - """ - Defaults to ACTIVE for newly created items - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/dataset_items/types/delete_dataset_item_response.py b/langfuse/api/resources/dataset_items/types/delete_dataset_item_response.py deleted file mode 100644 index 4d700ff75..000000000 --- a/langfuse/api/resources/dataset_items/types/delete_dataset_item_response.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class DeleteDatasetItemResponse(pydantic_v1.BaseModel): - message: str = pydantic_v1.Field() - """ - Success message after deletion - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/dataset_items/types/paginated_dataset_items.py b/langfuse/api/resources/dataset_items/types/paginated_dataset_items.py deleted file mode 100644 index 8592ba80f..000000000 --- a/langfuse/api/resources/dataset_items/types/paginated_dataset_items.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.dataset_item import DatasetItem -from ...utils.resources.pagination.types.meta_response import MetaResponse - - -class PaginatedDatasetItems(pydantic_v1.BaseModel): - data: typing.List[DatasetItem] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/dataset_run_items/__init__.py b/langfuse/api/resources/dataset_run_items/__init__.py deleted file mode 100644 index d522a3129..000000000 --- a/langfuse/api/resources/dataset_run_items/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import CreateDatasetRunItemRequest, PaginatedDatasetRunItems - -__all__ = ["CreateDatasetRunItemRequest", "PaginatedDatasetRunItems"] diff --git a/langfuse/api/resources/dataset_run_items/client.py b/langfuse/api/resources/dataset_run_items/client.py deleted file mode 100644 index 3664fde96..000000000 --- a/langfuse/api/resources/dataset_run_items/client.py +++ /dev/null @@ -1,366 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from ..commons.types.dataset_run_item import DatasetRunItem -from .types.create_dataset_run_item_request import CreateDatasetRunItemRequest -from .types.paginated_dataset_run_items import PaginatedDatasetRunItems - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class DatasetRunItemsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def create( - self, - *, - request: CreateDatasetRunItemRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> DatasetRunItem: - """ - Create a dataset run item - - Parameters - ---------- - request : CreateDatasetRunItemRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DatasetRunItem - - Examples - -------- - from langfuse import CreateDatasetRunItemRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.dataset_run_items.create( - request=CreateDatasetRunItemRequest( - run_name="runName", - dataset_item_id="datasetItemId", - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/dataset-run-items", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DatasetRunItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list( - self, - *, - dataset_id: str, - run_name: str, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedDatasetRunItems: - """ - List dataset run items - - Parameters - ---------- - dataset_id : str - - run_name : str - - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedDatasetRunItems - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.dataset_run_items.list( - dataset_id="datasetId", - run_name="runName", - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/dataset-run-items", - method="GET", - params={ - "datasetId": dataset_id, - "runName": run_name, - "page": page, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - PaginatedDatasetRunItems, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncDatasetRunItemsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def create( - self, - *, - request: CreateDatasetRunItemRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> DatasetRunItem: - """ - Create a dataset run item - - Parameters - ---------- - request : CreateDatasetRunItemRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DatasetRunItem - - Examples - -------- - import asyncio - - from langfuse import CreateDatasetRunItemRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.dataset_run_items.create( - request=CreateDatasetRunItemRequest( - run_name="runName", - dataset_item_id="datasetItemId", - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/dataset-run-items", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DatasetRunItem, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list( - self, - *, - dataset_id: str, - run_name: str, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedDatasetRunItems: - """ - List dataset run items - - Parameters - ---------- - dataset_id : str - - run_name : str - - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedDatasetRunItems - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.dataset_run_items.list( - dataset_id="datasetId", - run_name="runName", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/dataset-run-items", - method="GET", - params={ - "datasetId": dataset_id, - "runName": run_name, - "page": page, - "limit": limit, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - PaginatedDatasetRunItems, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/dataset_run_items/types/__init__.py b/langfuse/api/resources/dataset_run_items/types/__init__.py deleted file mode 100644 index e48e72c27..000000000 --- a/langfuse/api/resources/dataset_run_items/types/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .create_dataset_run_item_request import CreateDatasetRunItemRequest -from .paginated_dataset_run_items import PaginatedDatasetRunItems - -__all__ = ["CreateDatasetRunItemRequest", "PaginatedDatasetRunItems"] diff --git a/langfuse/api/resources/dataset_run_items/types/create_dataset_run_item_request.py b/langfuse/api/resources/dataset_run_items/types/create_dataset_run_item_request.py deleted file mode 100644 index 0a643b835..000000000 --- a/langfuse/api/resources/dataset_run_items/types/create_dataset_run_item_request.py +++ /dev/null @@ -1,64 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class CreateDatasetRunItemRequest(pydantic_v1.BaseModel): - run_name: str = pydantic_v1.Field(alias="runName") - run_description: typing.Optional[str] = pydantic_v1.Field( - alias="runDescription", default=None - ) - """ - Description of the run. If run exists, description will be updated. - """ - - metadata: typing.Optional[typing.Any] = pydantic_v1.Field(default=None) - """ - Metadata of the dataset run, updates run if run already exists - """ - - dataset_item_id: str = pydantic_v1.Field(alias="datasetItemId") - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - """ - traceId should always be provided. For compatibility with older SDK versions it can also be inferred from the provided observationId. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/dataset_run_items/types/paginated_dataset_run_items.py b/langfuse/api/resources/dataset_run_items/types/paginated_dataset_run_items.py deleted file mode 100644 index c1611bae0..000000000 --- a/langfuse/api/resources/dataset_run_items/types/paginated_dataset_run_items.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.dataset_run_item import DatasetRunItem -from ...utils.resources.pagination.types.meta_response import MetaResponse - - -class PaginatedDatasetRunItems(pydantic_v1.BaseModel): - data: typing.List[DatasetRunItem] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/datasets/__init__.py b/langfuse/api/resources/datasets/__init__.py deleted file mode 100644 index dd30a359d..000000000 --- a/langfuse/api/resources/datasets/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - CreateDatasetRequest, - DeleteDatasetRunResponse, - PaginatedDatasetRuns, - PaginatedDatasets, -) - -__all__ = [ - "CreateDatasetRequest", - "DeleteDatasetRunResponse", - "PaginatedDatasetRuns", - "PaginatedDatasets", -] diff --git a/langfuse/api/resources/datasets/client.py b/langfuse/api/resources/datasets/client.py deleted file mode 100644 index aff7293a0..000000000 --- a/langfuse/api/resources/datasets/client.py +++ /dev/null @@ -1,942 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from ..commons.types.dataset import Dataset -from ..commons.types.dataset_run_with_items import DatasetRunWithItems -from .types.create_dataset_request import CreateDatasetRequest -from .types.delete_dataset_run_response import DeleteDatasetRunResponse -from .types.paginated_dataset_runs import PaginatedDatasetRuns -from .types.paginated_datasets import PaginatedDatasets - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class DatasetsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def list( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedDatasets: - """ - Get all datasets - - Parameters - ---------- - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedDatasets - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.datasets.list() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/v2/datasets", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(PaginatedDatasets, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get( - self, - dataset_name: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> Dataset: - """ - Get a dataset - - Parameters - ---------- - dataset_name : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Dataset - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.datasets.get( - dataset_name="datasetName", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/v2/datasets/{jsonable_encoder(dataset_name)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Dataset, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create( - self, - *, - request: CreateDatasetRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> Dataset: - """ - Create a dataset - - Parameters - ---------- - request : CreateDatasetRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Dataset - - Examples - -------- - from langfuse import CreateDatasetRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.datasets.create( - request=CreateDatasetRequest( - name="name", - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/v2/datasets", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Dataset, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_run( - self, - dataset_name: str, - run_name: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> DatasetRunWithItems: - """ - Get a dataset run and its items - - Parameters - ---------- - dataset_name : str - - run_name : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DatasetRunWithItems - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.datasets.get_run( - dataset_name="datasetName", - run_name="runName", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs/{jsonable_encoder(run_name)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DatasetRunWithItems, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete_run( - self, - dataset_name: str, - run_name: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> DeleteDatasetRunResponse: - """ - Delete a dataset run and all its run items. This action is irreversible. - - Parameters - ---------- - dataset_name : str - - run_name : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteDatasetRunResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.datasets.delete_run( - dataset_name="datasetName", - run_name="runName", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs/{jsonable_encoder(run_name)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - DeleteDatasetRunResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_runs( - self, - dataset_name: str, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedDatasetRuns: - """ - Get dataset runs - - Parameters - ---------- - dataset_name : str - - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedDatasetRuns - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.datasets.get_runs( - dataset_name="datasetName", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(PaginatedDatasetRuns, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncDatasetsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedDatasets: - """ - Get all datasets - - Parameters - ---------- - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedDatasets - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.datasets.list() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/v2/datasets", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(PaginatedDatasets, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get( - self, - dataset_name: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> Dataset: - """ - Get a dataset - - Parameters - ---------- - dataset_name : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Dataset - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.datasets.get( - dataset_name="datasetName", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/v2/datasets/{jsonable_encoder(dataset_name)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Dataset, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create( - self, - *, - request: CreateDatasetRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> Dataset: - """ - Create a dataset - - Parameters - ---------- - request : CreateDatasetRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Dataset - - Examples - -------- - import asyncio - - from langfuse import CreateDatasetRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.datasets.create( - request=CreateDatasetRequest( - name="name", - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/v2/datasets", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Dataset, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_run( - self, - dataset_name: str, - run_name: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> DatasetRunWithItems: - """ - Get a dataset run and its items - - Parameters - ---------- - dataset_name : str - - run_name : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DatasetRunWithItems - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.datasets.get_run( - dataset_name="datasetName", - run_name="runName", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs/{jsonable_encoder(run_name)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DatasetRunWithItems, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete_run( - self, - dataset_name: str, - run_name: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> DeleteDatasetRunResponse: - """ - Delete a dataset run and all its run items. This action is irreversible. - - Parameters - ---------- - dataset_name : str - - run_name : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - DeleteDatasetRunResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.datasets.delete_run( - dataset_name="datasetName", - run_name="runName", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs/{jsonable_encoder(run_name)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - DeleteDatasetRunResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_runs( - self, - dataset_name: str, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedDatasetRuns: - """ - Get dataset runs - - Parameters - ---------- - dataset_name : str - - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedDatasetRuns - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.datasets.get_runs( - dataset_name="datasetName", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/datasets/{jsonable_encoder(dataset_name)}/runs", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(PaginatedDatasetRuns, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/datasets/types/__init__.py b/langfuse/api/resources/datasets/types/__init__.py deleted file mode 100644 index f3304a59f..000000000 --- a/langfuse/api/resources/datasets/types/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .create_dataset_request import CreateDatasetRequest -from .delete_dataset_run_response import DeleteDatasetRunResponse -from .paginated_dataset_runs import PaginatedDatasetRuns -from .paginated_datasets import PaginatedDatasets - -__all__ = [ - "CreateDatasetRequest", - "DeleteDatasetRunResponse", - "PaginatedDatasetRuns", - "PaginatedDatasets", -] diff --git a/langfuse/api/resources/datasets/types/create_dataset_request.py b/langfuse/api/resources/datasets/types/create_dataset_request.py deleted file mode 100644 index 228527909..000000000 --- a/langfuse/api/resources/datasets/types/create_dataset_request.py +++ /dev/null @@ -1,59 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class CreateDatasetRequest(pydantic_v1.BaseModel): - name: str - description: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - input_schema: typing.Optional[typing.Any] = pydantic_v1.Field( - alias="inputSchema", default=None - ) - """ - JSON Schema for validating dataset item inputs. When set, all new and existing dataset items will be validated against this schema. - """ - - expected_output_schema: typing.Optional[typing.Any] = pydantic_v1.Field( - alias="expectedOutputSchema", default=None - ) - """ - JSON Schema for validating dataset item expected outputs. When set, all new and existing dataset items will be validated against this schema. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/datasets/types/delete_dataset_run_response.py b/langfuse/api/resources/datasets/types/delete_dataset_run_response.py deleted file mode 100644 index cf52eca14..000000000 --- a/langfuse/api/resources/datasets/types/delete_dataset_run_response.py +++ /dev/null @@ -1,42 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class DeleteDatasetRunResponse(pydantic_v1.BaseModel): - message: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/datasets/types/paginated_dataset_runs.py b/langfuse/api/resources/datasets/types/paginated_dataset_runs.py deleted file mode 100644 index 86f2f0a73..000000000 --- a/langfuse/api/resources/datasets/types/paginated_dataset_runs.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.dataset_run import DatasetRun -from ...utils.resources.pagination.types.meta_response import MetaResponse - - -class PaginatedDatasetRuns(pydantic_v1.BaseModel): - data: typing.List[DatasetRun] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/datasets/types/paginated_datasets.py b/langfuse/api/resources/datasets/types/paginated_datasets.py deleted file mode 100644 index c2d436bf4..000000000 --- a/langfuse/api/resources/datasets/types/paginated_datasets.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.dataset import Dataset -from ...utils.resources.pagination.types.meta_response import MetaResponse - - -class PaginatedDatasets(pydantic_v1.BaseModel): - data: typing.List[Dataset] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/health/__init__.py b/langfuse/api/resources/health/__init__.py deleted file mode 100644 index f468cdffb..000000000 --- a/langfuse/api/resources/health/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import HealthResponse -from .errors import ServiceUnavailableError - -__all__ = ["HealthResponse", "ServiceUnavailableError"] diff --git a/langfuse/api/resources/health/client.py b/langfuse/api/resources/health/client.py deleted file mode 100644 index 029be7a0c..000000000 --- a/langfuse/api/resources/health/client.py +++ /dev/null @@ -1,154 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from .errors.service_unavailable_error import ServiceUnavailableError -from .types.health_response import HealthResponse - - -class HealthClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def health( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> HealthResponse: - """ - Check health of API and database - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HealthResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.health.health() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/health", method="GET", request_options=request_options - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(HealthResponse, _response.json()) # type: ignore - if _response.status_code == 503: - raise ServiceUnavailableError() - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncHealthClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def health( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> HealthResponse: - """ - Check health of API and database - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - HealthResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.health.health() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/health", method="GET", request_options=request_options - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(HealthResponse, _response.json()) # type: ignore - if _response.status_code == 503: - raise ServiceUnavailableError() - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/health/errors/__init__.py b/langfuse/api/resources/health/errors/__init__.py deleted file mode 100644 index 46bb3fedd..000000000 --- a/langfuse/api/resources/health/errors/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .service_unavailable_error import ServiceUnavailableError - -__all__ = ["ServiceUnavailableError"] diff --git a/langfuse/api/resources/health/errors/service_unavailable_error.py b/langfuse/api/resources/health/errors/service_unavailable_error.py deleted file mode 100644 index acfd8fbf3..000000000 --- a/langfuse/api/resources/health/errors/service_unavailable_error.py +++ /dev/null @@ -1,8 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from ....core.api_error import ApiError - - -class ServiceUnavailableError(ApiError): - def __init__(self) -> None: - super().__init__(status_code=503) diff --git a/langfuse/api/resources/health/types/__init__.py b/langfuse/api/resources/health/types/__init__.py deleted file mode 100644 index 5fb7ec574..000000000 --- a/langfuse/api/resources/health/types/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .health_response import HealthResponse - -__all__ = ["HealthResponse"] diff --git a/langfuse/api/resources/health/types/health_response.py b/langfuse/api/resources/health/types/health_response.py deleted file mode 100644 index 633da67a8..000000000 --- a/langfuse/api/resources/health/types/health_response.py +++ /dev/null @@ -1,58 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class HealthResponse(pydantic_v1.BaseModel): - """ - Examples - -------- - from langfuse import HealthResponse - - HealthResponse( - version="1.25.0", - status="OK", - ) - """ - - version: str = pydantic_v1.Field() - """ - Langfuse server version - """ - - status: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/__init__.py b/langfuse/api/resources/ingestion/__init__.py deleted file mode 100644 index 9e072dc17..000000000 --- a/langfuse/api/resources/ingestion/__init__.py +++ /dev/null @@ -1,91 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - BaseEvent, - CreateEventBody, - CreateEventEvent, - CreateGenerationBody, - CreateGenerationEvent, - CreateObservationEvent, - CreateSpanBody, - CreateSpanEvent, - IngestionError, - IngestionEvent, - IngestionEvent_EventCreate, - IngestionEvent_GenerationCreate, - IngestionEvent_GenerationUpdate, - IngestionEvent_ObservationCreate, - IngestionEvent_ObservationUpdate, - IngestionEvent_ScoreCreate, - IngestionEvent_SdkLog, - IngestionEvent_SpanCreate, - IngestionEvent_SpanUpdate, - IngestionEvent_TraceCreate, - IngestionResponse, - IngestionSuccess, - IngestionUsage, - ObservationBody, - ObservationType, - OpenAiCompletionUsageSchema, - OpenAiResponseUsageSchema, - OpenAiUsage, - OptionalObservationBody, - ScoreBody, - ScoreEvent, - SdkLogBody, - SdkLogEvent, - TraceBody, - TraceEvent, - UpdateEventBody, - UpdateGenerationBody, - UpdateGenerationEvent, - UpdateObservationEvent, - UpdateSpanBody, - UpdateSpanEvent, - UsageDetails, -) - -__all__ = [ - "BaseEvent", - "CreateEventBody", - "CreateEventEvent", - "CreateGenerationBody", - "CreateGenerationEvent", - "CreateObservationEvent", - "CreateSpanBody", - "CreateSpanEvent", - "IngestionError", - "IngestionEvent", - "IngestionEvent_EventCreate", - "IngestionEvent_GenerationCreate", - "IngestionEvent_GenerationUpdate", - "IngestionEvent_ObservationCreate", - "IngestionEvent_ObservationUpdate", - "IngestionEvent_ScoreCreate", - "IngestionEvent_SdkLog", - "IngestionEvent_SpanCreate", - "IngestionEvent_SpanUpdate", - "IngestionEvent_TraceCreate", - "IngestionResponse", - "IngestionSuccess", - "IngestionUsage", - "ObservationBody", - "ObservationType", - "OpenAiCompletionUsageSchema", - "OpenAiResponseUsageSchema", - "OpenAiUsage", - "OptionalObservationBody", - "ScoreBody", - "ScoreEvent", - "SdkLogBody", - "SdkLogEvent", - "TraceBody", - "TraceEvent", - "UpdateEventBody", - "UpdateGenerationBody", - "UpdateGenerationEvent", - "UpdateObservationEvent", - "UpdateSpanBody", - "UpdateSpanEvent", - "UsageDetails", -] diff --git a/langfuse/api/resources/ingestion/types/__init__.py b/langfuse/api/resources/ingestion/types/__init__.py deleted file mode 100644 index a3490e4dc..000000000 --- a/langfuse/api/resources/ingestion/types/__init__.py +++ /dev/null @@ -1,91 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .base_event import BaseEvent -from .create_event_body import CreateEventBody -from .create_event_event import CreateEventEvent -from .create_generation_body import CreateGenerationBody -from .create_generation_event import CreateGenerationEvent -from .create_observation_event import CreateObservationEvent -from .create_span_body import CreateSpanBody -from .create_span_event import CreateSpanEvent -from .ingestion_error import IngestionError -from .ingestion_event import ( - IngestionEvent, - IngestionEvent_EventCreate, - IngestionEvent_GenerationCreate, - IngestionEvent_GenerationUpdate, - IngestionEvent_ObservationCreate, - IngestionEvent_ObservationUpdate, - IngestionEvent_ScoreCreate, - IngestionEvent_SdkLog, - IngestionEvent_SpanCreate, - IngestionEvent_SpanUpdate, - IngestionEvent_TraceCreate, -) -from .ingestion_response import IngestionResponse -from .ingestion_success import IngestionSuccess -from .ingestion_usage import IngestionUsage -from .observation_body import ObservationBody -from .observation_type import ObservationType -from .open_ai_completion_usage_schema import OpenAiCompletionUsageSchema -from .open_ai_response_usage_schema import OpenAiResponseUsageSchema -from .open_ai_usage import OpenAiUsage -from .optional_observation_body import OptionalObservationBody -from .score_body import ScoreBody -from .score_event import ScoreEvent -from .sdk_log_body import SdkLogBody -from .sdk_log_event import SdkLogEvent -from .trace_body import TraceBody -from .trace_event import TraceEvent -from .update_event_body import UpdateEventBody -from .update_generation_body import UpdateGenerationBody -from .update_generation_event import UpdateGenerationEvent -from .update_observation_event import UpdateObservationEvent -from .update_span_body import UpdateSpanBody -from .update_span_event import UpdateSpanEvent -from .usage_details import UsageDetails - -__all__ = [ - "BaseEvent", - "CreateEventBody", - "CreateEventEvent", - "CreateGenerationBody", - "CreateGenerationEvent", - "CreateObservationEvent", - "CreateSpanBody", - "CreateSpanEvent", - "IngestionError", - "IngestionEvent", - "IngestionEvent_EventCreate", - "IngestionEvent_GenerationCreate", - "IngestionEvent_GenerationUpdate", - "IngestionEvent_ObservationCreate", - "IngestionEvent_ObservationUpdate", - "IngestionEvent_ScoreCreate", - "IngestionEvent_SdkLog", - "IngestionEvent_SpanCreate", - "IngestionEvent_SpanUpdate", - "IngestionEvent_TraceCreate", - "IngestionResponse", - "IngestionSuccess", - "IngestionUsage", - "ObservationBody", - "ObservationType", - "OpenAiCompletionUsageSchema", - "OpenAiResponseUsageSchema", - "OpenAiUsage", - "OptionalObservationBody", - "ScoreBody", - "ScoreEvent", - "SdkLogBody", - "SdkLogEvent", - "TraceBody", - "TraceEvent", - "UpdateEventBody", - "UpdateGenerationBody", - "UpdateGenerationEvent", - "UpdateObservationEvent", - "UpdateSpanBody", - "UpdateSpanEvent", - "UsageDetails", -] diff --git a/langfuse/api/resources/ingestion/types/base_event.py b/langfuse/api/resources/ingestion/types/base_event.py deleted file mode 100644 index dec8a52e7..000000000 --- a/langfuse/api/resources/ingestion/types/base_event.py +++ /dev/null @@ -1,55 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class BaseEvent(pydantic_v1.BaseModel): - id: str = pydantic_v1.Field() - """ - UUID v4 that identifies the event - """ - - timestamp: str = pydantic_v1.Field() - """ - Datetime (ISO 8601) of event creation in client. Should be as close to actual event creation in client as possible, this timestamp will be used for ordering of events in future release. Resolution: milliseconds (required), microseconds (optimal). - """ - - metadata: typing.Optional[typing.Any] = pydantic_v1.Field(default=None) - """ - Optional. Metadata field used by the Langfuse SDKs for debugging. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/create_event_body.py b/langfuse/api/resources/ingestion/types/create_event_body.py deleted file mode 100644 index afe8677f3..000000000 --- a/langfuse/api/resources/ingestion/types/create_event_body.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .optional_observation_body import OptionalObservationBody - - -class CreateEventBody(OptionalObservationBody): - id: typing.Optional[str] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/create_event_event.py b/langfuse/api/resources/ingestion/types/create_event_event.py deleted file mode 100644 index 0c3cce040..000000000 --- a/langfuse/api/resources/ingestion/types/create_event_event.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_event import BaseEvent -from .create_event_body import CreateEventBody - - -class CreateEventEvent(BaseEvent): - body: CreateEventBody - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/create_generation_body.py b/langfuse/api/resources/ingestion/types/create_generation_body.py deleted file mode 100644 index 428b58607..000000000 --- a/langfuse/api/resources/ingestion/types/create_generation_body.py +++ /dev/null @@ -1,67 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.map_value import MapValue -from .create_span_body import CreateSpanBody -from .ingestion_usage import IngestionUsage -from .usage_details import UsageDetails - - -class CreateGenerationBody(CreateSpanBody): - completion_start_time: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="completionStartTime", default=None - ) - model: typing.Optional[str] = None - model_parameters: typing.Optional[typing.Dict[str, MapValue]] = pydantic_v1.Field( - alias="modelParameters", default=None - ) - usage: typing.Optional[IngestionUsage] = None - usage_details: typing.Optional[UsageDetails] = pydantic_v1.Field( - alias="usageDetails", default=None - ) - cost_details: typing.Optional[typing.Dict[str, float]] = pydantic_v1.Field( - alias="costDetails", default=None - ) - prompt_name: typing.Optional[str] = pydantic_v1.Field( - alias="promptName", default=None - ) - prompt_version: typing.Optional[int] = pydantic_v1.Field( - alias="promptVersion", default=None - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/create_generation_event.py b/langfuse/api/resources/ingestion/types/create_generation_event.py deleted file mode 100644 index cb7b484dd..000000000 --- a/langfuse/api/resources/ingestion/types/create_generation_event.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_event import BaseEvent -from .create_generation_body import CreateGenerationBody - - -class CreateGenerationEvent(BaseEvent): - body: CreateGenerationBody - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/create_observation_event.py b/langfuse/api/resources/ingestion/types/create_observation_event.py deleted file mode 100644 index adfefc793..000000000 --- a/langfuse/api/resources/ingestion/types/create_observation_event.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_event import BaseEvent -from .observation_body import ObservationBody - - -class CreateObservationEvent(BaseEvent): - body: ObservationBody - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/create_span_body.py b/langfuse/api/resources/ingestion/types/create_span_body.py deleted file mode 100644 index c31fde567..000000000 --- a/langfuse/api/resources/ingestion/types/create_span_body.py +++ /dev/null @@ -1,47 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .create_event_body import CreateEventBody - - -class CreateSpanBody(CreateEventBody): - end_time: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="endTime", default=None - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/create_span_event.py b/langfuse/api/resources/ingestion/types/create_span_event.py deleted file mode 100644 index 7a8e8154c..000000000 --- a/langfuse/api/resources/ingestion/types/create_span_event.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_event import BaseEvent -from .create_span_body import CreateSpanBody - - -class CreateSpanEvent(BaseEvent): - body: CreateSpanBody - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/ingestion_error.py b/langfuse/api/resources/ingestion/types/ingestion_error.py deleted file mode 100644 index b9028ce1d..000000000 --- a/langfuse/api/resources/ingestion/types/ingestion_error.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class IngestionError(pydantic_v1.BaseModel): - id: str - status: int - message: typing.Optional[str] = None - error: typing.Optional[typing.Any] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/ingestion_event.py b/langfuse/api/resources/ingestion/types/ingestion_event.py deleted file mode 100644 index e083c9354..000000000 --- a/langfuse/api/resources/ingestion/types/ingestion_event.py +++ /dev/null @@ -1,422 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from __future__ import annotations - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .create_event_body import CreateEventBody -from .create_generation_body import CreateGenerationBody -from .create_span_body import CreateSpanBody -from .observation_body import ObservationBody -from .score_body import ScoreBody -from .sdk_log_body import SdkLogBody -from .trace_body import TraceBody -from .update_generation_body import UpdateGenerationBody -from .update_span_body import UpdateSpanBody - - -class IngestionEvent_TraceCreate(pydantic_v1.BaseModel): - body: TraceBody - id: str - timestamp: str - metadata: typing.Optional[typing.Any] = None - type: typing.Literal["trace-create"] = "trace-create" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class IngestionEvent_ScoreCreate(pydantic_v1.BaseModel): - body: ScoreBody - id: str - timestamp: str - metadata: typing.Optional[typing.Any] = None - type: typing.Literal["score-create"] = "score-create" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class IngestionEvent_SpanCreate(pydantic_v1.BaseModel): - body: CreateSpanBody - id: str - timestamp: str - metadata: typing.Optional[typing.Any] = None - type: typing.Literal["span-create"] = "span-create" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class IngestionEvent_SpanUpdate(pydantic_v1.BaseModel): - body: UpdateSpanBody - id: str - timestamp: str - metadata: typing.Optional[typing.Any] = None - type: typing.Literal["span-update"] = "span-update" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class IngestionEvent_GenerationCreate(pydantic_v1.BaseModel): - body: CreateGenerationBody - id: str - timestamp: str - metadata: typing.Optional[typing.Any] = None - type: typing.Literal["generation-create"] = "generation-create" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class IngestionEvent_GenerationUpdate(pydantic_v1.BaseModel): - body: UpdateGenerationBody - id: str - timestamp: str - metadata: typing.Optional[typing.Any] = None - type: typing.Literal["generation-update"] = "generation-update" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class IngestionEvent_EventCreate(pydantic_v1.BaseModel): - body: CreateEventBody - id: str - timestamp: str - metadata: typing.Optional[typing.Any] = None - type: typing.Literal["event-create"] = "event-create" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class IngestionEvent_SdkLog(pydantic_v1.BaseModel): - body: SdkLogBody - id: str - timestamp: str - metadata: typing.Optional[typing.Any] = None - type: typing.Literal["sdk-log"] = "sdk-log" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class IngestionEvent_ObservationCreate(pydantic_v1.BaseModel): - body: ObservationBody - id: str - timestamp: str - metadata: typing.Optional[typing.Any] = None - type: typing.Literal["observation-create"] = "observation-create" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class IngestionEvent_ObservationUpdate(pydantic_v1.BaseModel): - body: ObservationBody - id: str - timestamp: str - metadata: typing.Optional[typing.Any] = None - type: typing.Literal["observation-update"] = "observation-update" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -IngestionEvent = typing.Union[ - IngestionEvent_TraceCreate, - IngestionEvent_ScoreCreate, - IngestionEvent_SpanCreate, - IngestionEvent_SpanUpdate, - IngestionEvent_GenerationCreate, - IngestionEvent_GenerationUpdate, - IngestionEvent_EventCreate, - IngestionEvent_SdkLog, - IngestionEvent_ObservationCreate, - IngestionEvent_ObservationUpdate, -] diff --git a/langfuse/api/resources/ingestion/types/ingestion_response.py b/langfuse/api/resources/ingestion/types/ingestion_response.py deleted file mode 100644 index b4e66349c..000000000 --- a/langfuse/api/resources/ingestion/types/ingestion_response.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .ingestion_error import IngestionError -from .ingestion_success import IngestionSuccess - - -class IngestionResponse(pydantic_v1.BaseModel): - successes: typing.List[IngestionSuccess] - errors: typing.List[IngestionError] - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/ingestion_success.py b/langfuse/api/resources/ingestion/types/ingestion_success.py deleted file mode 100644 index 481e64752..000000000 --- a/langfuse/api/resources/ingestion/types/ingestion_success.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class IngestionSuccess(pydantic_v1.BaseModel): - id: str - status: int - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/observation_body.py b/langfuse/api/resources/ingestion/types/observation_body.py deleted file mode 100644 index d191a1f12..000000000 --- a/langfuse/api/resources/ingestion/types/observation_body.py +++ /dev/null @@ -1,77 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.map_value import MapValue -from ...commons.types.observation_level import ObservationLevel -from ...commons.types.usage import Usage -from .observation_type import ObservationType - - -class ObservationBody(pydantic_v1.BaseModel): - id: typing.Optional[str] = None - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - type: ObservationType - name: typing.Optional[str] = None - start_time: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="startTime", default=None - ) - end_time: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="endTime", default=None - ) - completion_start_time: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="completionStartTime", default=None - ) - model: typing.Optional[str] = None - model_parameters: typing.Optional[typing.Dict[str, MapValue]] = pydantic_v1.Field( - alias="modelParameters", default=None - ) - input: typing.Optional[typing.Any] = None - version: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - output: typing.Optional[typing.Any] = None - usage: typing.Optional[Usage] = None - level: typing.Optional[ObservationLevel] = None - status_message: typing.Optional[str] = pydantic_v1.Field( - alias="statusMessage", default=None - ) - parent_observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="parentObservationId", default=None - ) - environment: typing.Optional[str] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/observation_type.py b/langfuse/api/resources/ingestion/types/observation_type.py deleted file mode 100644 index 2f11300ff..000000000 --- a/langfuse/api/resources/ingestion/types/observation_type.py +++ /dev/null @@ -1,53 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class ObservationType(str, enum.Enum): - SPAN = "SPAN" - GENERATION = "GENERATION" - EVENT = "EVENT" - AGENT = "AGENT" - TOOL = "TOOL" - CHAIN = "CHAIN" - RETRIEVER = "RETRIEVER" - EVALUATOR = "EVALUATOR" - EMBEDDING = "EMBEDDING" - GUARDRAIL = "GUARDRAIL" - - def visit( - self, - span: typing.Callable[[], T_Result], - generation: typing.Callable[[], T_Result], - event: typing.Callable[[], T_Result], - agent: typing.Callable[[], T_Result], - tool: typing.Callable[[], T_Result], - chain: typing.Callable[[], T_Result], - retriever: typing.Callable[[], T_Result], - evaluator: typing.Callable[[], T_Result], - embedding: typing.Callable[[], T_Result], - guardrail: typing.Callable[[], T_Result], - ) -> T_Result: - if self is ObservationType.SPAN: - return span() - if self is ObservationType.GENERATION: - return generation() - if self is ObservationType.EVENT: - return event() - if self is ObservationType.AGENT: - return agent() - if self is ObservationType.TOOL: - return tool() - if self is ObservationType.CHAIN: - return chain() - if self is ObservationType.RETRIEVER: - return retriever() - if self is ObservationType.EVALUATOR: - return evaluator() - if self is ObservationType.EMBEDDING: - return embedding() - if self is ObservationType.GUARDRAIL: - return guardrail() diff --git a/langfuse/api/resources/ingestion/types/open_ai_completion_usage_schema.py b/langfuse/api/resources/ingestion/types/open_ai_completion_usage_schema.py deleted file mode 100644 index 368a7da03..000000000 --- a/langfuse/api/resources/ingestion/types/open_ai_completion_usage_schema.py +++ /dev/null @@ -1,54 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class OpenAiCompletionUsageSchema(pydantic_v1.BaseModel): - """ - OpenAI Usage schema from (Chat-)Completion APIs - """ - - prompt_tokens: int - completion_tokens: int - total_tokens: int - prompt_tokens_details: typing.Optional[typing.Dict[str, typing.Optional[int]]] = ( - None - ) - completion_tokens_details: typing.Optional[ - typing.Dict[str, typing.Optional[int]] - ] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/open_ai_response_usage_schema.py b/langfuse/api/resources/ingestion/types/open_ai_response_usage_schema.py deleted file mode 100644 index 0c68e6a7d..000000000 --- a/langfuse/api/resources/ingestion/types/open_ai_response_usage_schema.py +++ /dev/null @@ -1,52 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class OpenAiResponseUsageSchema(pydantic_v1.BaseModel): - """ - OpenAI Usage schema from Response API - """ - - input_tokens: int - output_tokens: int - total_tokens: int - input_tokens_details: typing.Optional[typing.Dict[str, typing.Optional[int]]] = None - output_tokens_details: typing.Optional[typing.Dict[str, typing.Optional[int]]] = ( - None - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/open_ai_usage.py b/langfuse/api/resources/ingestion/types/open_ai_usage.py deleted file mode 100644 index 86e7ebd82..000000000 --- a/langfuse/api/resources/ingestion/types/open_ai_usage.py +++ /dev/null @@ -1,56 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class OpenAiUsage(pydantic_v1.BaseModel): - """ - Usage interface of OpenAI for improved compatibility. - """ - - prompt_tokens: typing.Optional[int] = pydantic_v1.Field( - alias="promptTokens", default=None - ) - completion_tokens: typing.Optional[int] = pydantic_v1.Field( - alias="completionTokens", default=None - ) - total_tokens: typing.Optional[int] = pydantic_v1.Field( - alias="totalTokens", default=None - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/optional_observation_body.py b/langfuse/api/resources/ingestion/types/optional_observation_body.py deleted file mode 100644 index 7302d30f9..000000000 --- a/langfuse/api/resources/ingestion/types/optional_observation_body.py +++ /dev/null @@ -1,61 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.observation_level import ObservationLevel - - -class OptionalObservationBody(pydantic_v1.BaseModel): - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - name: typing.Optional[str] = None - start_time: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="startTime", default=None - ) - metadata: typing.Optional[typing.Any] = None - input: typing.Optional[typing.Any] = None - output: typing.Optional[typing.Any] = None - level: typing.Optional[ObservationLevel] = None - status_message: typing.Optional[str] = pydantic_v1.Field( - alias="statusMessage", default=None - ) - parent_observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="parentObservationId", default=None - ) - version: typing.Optional[str] = None - environment: typing.Optional[str] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/score_body.py b/langfuse/api/resources/ingestion/types/score_body.py deleted file mode 100644 index 549046564..000000000 --- a/langfuse/api/resources/ingestion/types/score_body.py +++ /dev/null @@ -1,93 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.create_score_value import CreateScoreValue -from ...commons.types.score_data_type import ScoreDataType - - -class ScoreBody(pydantic_v1.BaseModel): - """ - Examples - -------- - from langfuse import ScoreBody - - ScoreBody( - name="novelty", - value=0.9, - trace_id="cdef-1234-5678-90ab", - ) - """ - - id: typing.Optional[str] = None - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - session_id: typing.Optional[str] = pydantic_v1.Field( - alias="sessionId", default=None - ) - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - dataset_run_id: typing.Optional[str] = pydantic_v1.Field( - alias="datasetRunId", default=None - ) - name: str - environment: typing.Optional[str] = None - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - """ - The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. - """ - - value: CreateScoreValue = pydantic_v1.Field() - """ - The value of the score. Must be passed as string for categorical scores, and numeric for boolean and numeric scores. Boolean score values must equal either 1 or 0 (true or false) - """ - - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - data_type: typing.Optional[ScoreDataType] = pydantic_v1.Field( - alias="dataType", default=None - ) - """ - When set, must match the score value's type. If not set, will be inferred from the score value or config - """ - - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - """ - Reference a score config on a score. When set, the score name must equal the config name and scores must comply with the config's range and data type. For categorical scores, the value must map to a config category. Numeric scores might be constrained by the score config's max and min values - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/score_event.py b/langfuse/api/resources/ingestion/types/score_event.py deleted file mode 100644 index ea05aedef..000000000 --- a/langfuse/api/resources/ingestion/types/score_event.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_event import BaseEvent -from .score_body import ScoreBody - - -class ScoreEvent(BaseEvent): - body: ScoreBody - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/sdk_log_body.py b/langfuse/api/resources/ingestion/types/sdk_log_body.py deleted file mode 100644 index df8972860..000000000 --- a/langfuse/api/resources/ingestion/types/sdk_log_body.py +++ /dev/null @@ -1,42 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class SdkLogBody(pydantic_v1.BaseModel): - log: typing.Any - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/sdk_log_event.py b/langfuse/api/resources/ingestion/types/sdk_log_event.py deleted file mode 100644 index d7ad87de8..000000000 --- a/langfuse/api/resources/ingestion/types/sdk_log_event.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_event import BaseEvent -from .sdk_log_body import SdkLogBody - - -class SdkLogEvent(BaseEvent): - body: SdkLogBody - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/trace_body.py b/langfuse/api/resources/ingestion/types/trace_body.py deleted file mode 100644 index 3f5550435..000000000 --- a/langfuse/api/resources/ingestion/types/trace_body.py +++ /dev/null @@ -1,61 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class TraceBody(pydantic_v1.BaseModel): - id: typing.Optional[str] = None - timestamp: typing.Optional[dt.datetime] = None - name: typing.Optional[str] = None - user_id: typing.Optional[str] = pydantic_v1.Field(alias="userId", default=None) - input: typing.Optional[typing.Any] = None - output: typing.Optional[typing.Any] = None - session_id: typing.Optional[str] = pydantic_v1.Field( - alias="sessionId", default=None - ) - release: typing.Optional[str] = None - version: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - tags: typing.Optional[typing.List[str]] = None - environment: typing.Optional[str] = None - public: typing.Optional[bool] = pydantic_v1.Field(default=None) - """ - Make trace publicly accessible via url - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/trace_event.py b/langfuse/api/resources/ingestion/types/trace_event.py deleted file mode 100644 index b84ddd615..000000000 --- a/langfuse/api/resources/ingestion/types/trace_event.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_event import BaseEvent -from .trace_body import TraceBody - - -class TraceEvent(BaseEvent): - body: TraceBody - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/update_event_body.py b/langfuse/api/resources/ingestion/types/update_event_body.py deleted file mode 100644 index 35bbb359b..000000000 --- a/langfuse/api/resources/ingestion/types/update_event_body.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .optional_observation_body import OptionalObservationBody - - -class UpdateEventBody(OptionalObservationBody): - id: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/update_generation_body.py b/langfuse/api/resources/ingestion/types/update_generation_body.py deleted file mode 100644 index 2058543af..000000000 --- a/langfuse/api/resources/ingestion/types/update_generation_body.py +++ /dev/null @@ -1,67 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.map_value import MapValue -from .ingestion_usage import IngestionUsage -from .update_span_body import UpdateSpanBody -from .usage_details import UsageDetails - - -class UpdateGenerationBody(UpdateSpanBody): - completion_start_time: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="completionStartTime", default=None - ) - model: typing.Optional[str] = None - model_parameters: typing.Optional[typing.Dict[str, MapValue]] = pydantic_v1.Field( - alias="modelParameters", default=None - ) - usage: typing.Optional[IngestionUsage] = None - prompt_name: typing.Optional[str] = pydantic_v1.Field( - alias="promptName", default=None - ) - usage_details: typing.Optional[UsageDetails] = pydantic_v1.Field( - alias="usageDetails", default=None - ) - cost_details: typing.Optional[typing.Dict[str, float]] = pydantic_v1.Field( - alias="costDetails", default=None - ) - prompt_version: typing.Optional[int] = pydantic_v1.Field( - alias="promptVersion", default=None - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/update_generation_event.py b/langfuse/api/resources/ingestion/types/update_generation_event.py deleted file mode 100644 index da8f6a9fa..000000000 --- a/langfuse/api/resources/ingestion/types/update_generation_event.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_event import BaseEvent -from .update_generation_body import UpdateGenerationBody - - -class UpdateGenerationEvent(BaseEvent): - body: UpdateGenerationBody - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/update_observation_event.py b/langfuse/api/resources/ingestion/types/update_observation_event.py deleted file mode 100644 index 9d7af357f..000000000 --- a/langfuse/api/resources/ingestion/types/update_observation_event.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_event import BaseEvent -from .observation_body import ObservationBody - - -class UpdateObservationEvent(BaseEvent): - body: ObservationBody - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/update_span_body.py b/langfuse/api/resources/ingestion/types/update_span_body.py deleted file mode 100644 index e3484879b..000000000 --- a/langfuse/api/resources/ingestion/types/update_span_body.py +++ /dev/null @@ -1,47 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .update_event_body import UpdateEventBody - - -class UpdateSpanBody(UpdateEventBody): - end_time: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="endTime", default=None - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/ingestion/types/update_span_event.py b/langfuse/api/resources/ingestion/types/update_span_event.py deleted file mode 100644 index ec7d83b15..000000000 --- a/langfuse/api/resources/ingestion/types/update_span_event.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_event import BaseEvent -from .update_span_body import UpdateSpanBody - - -class UpdateSpanEvent(BaseEvent): - body: UpdateSpanBody - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/llm_connections/__init__.py b/langfuse/api/resources/llm_connections/__init__.py deleted file mode 100644 index 3cf778f1b..000000000 --- a/langfuse/api/resources/llm_connections/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - LlmAdapter, - LlmConnection, - PaginatedLlmConnections, - UpsertLlmConnectionRequest, -) - -__all__ = [ - "LlmAdapter", - "LlmConnection", - "PaginatedLlmConnections", - "UpsertLlmConnectionRequest", -] diff --git a/langfuse/api/resources/llm_connections/client.py b/langfuse/api/resources/llm_connections/client.py deleted file mode 100644 index 4497598c5..000000000 --- a/langfuse/api/resources/llm_connections/client.py +++ /dev/null @@ -1,340 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from .types.llm_connection import LlmConnection -from .types.paginated_llm_connections import PaginatedLlmConnections -from .types.upsert_llm_connection_request import UpsertLlmConnectionRequest - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class LlmConnectionsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def list( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedLlmConnections: - """ - Get all LLM connections in a project - - Parameters - ---------- - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedLlmConnections - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.llm_connections.list() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/llm-connections", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - PaginatedLlmConnections, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def upsert( - self, - *, - request: UpsertLlmConnectionRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> LlmConnection: - """ - Create or update an LLM connection. The connection is upserted on provider. - - Parameters - ---------- - request : UpsertLlmConnectionRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - LlmConnection - - Examples - -------- - from langfuse import LlmAdapter, UpsertLlmConnectionRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.llm_connections.upsert( - request=UpsertLlmConnectionRequest( - provider="provider", - adapter=LlmAdapter.ANTHROPIC, - secret_key="secretKey", - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/llm-connections", - method="PUT", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(LlmConnection, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncLlmConnectionsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedLlmConnections: - """ - Get all LLM connections in a project - - Parameters - ---------- - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedLlmConnections - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.llm_connections.list() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/llm-connections", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - PaginatedLlmConnections, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def upsert( - self, - *, - request: UpsertLlmConnectionRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> LlmConnection: - """ - Create or update an LLM connection. The connection is upserted on provider. - - Parameters - ---------- - request : UpsertLlmConnectionRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - LlmConnection - - Examples - -------- - import asyncio - - from langfuse import LlmAdapter, UpsertLlmConnectionRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.llm_connections.upsert( - request=UpsertLlmConnectionRequest( - provider="provider", - adapter=LlmAdapter.ANTHROPIC, - secret_key="secretKey", - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/llm-connections", - method="PUT", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(LlmConnection, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/llm_connections/types/__init__.py b/langfuse/api/resources/llm_connections/types/__init__.py deleted file mode 100644 index b490e6e27..000000000 --- a/langfuse/api/resources/llm_connections/types/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .llm_adapter import LlmAdapter -from .llm_connection import LlmConnection -from .paginated_llm_connections import PaginatedLlmConnections -from .upsert_llm_connection_request import UpsertLlmConnectionRequest - -__all__ = [ - "LlmAdapter", - "LlmConnection", - "PaginatedLlmConnections", - "UpsertLlmConnectionRequest", -] diff --git a/langfuse/api/resources/llm_connections/types/llm_adapter.py b/langfuse/api/resources/llm_connections/types/llm_adapter.py deleted file mode 100644 index d03513aeb..000000000 --- a/langfuse/api/resources/llm_connections/types/llm_adapter.py +++ /dev/null @@ -1,37 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class LlmAdapter(str, enum.Enum): - ANTHROPIC = "anthropic" - OPEN_AI = "openai" - AZURE = "azure" - BEDROCK = "bedrock" - GOOGLE_VERTEX_AI = "google-vertex-ai" - GOOGLE_AI_STUDIO = "google-ai-studio" - - def visit( - self, - anthropic: typing.Callable[[], T_Result], - open_ai: typing.Callable[[], T_Result], - azure: typing.Callable[[], T_Result], - bedrock: typing.Callable[[], T_Result], - google_vertex_ai: typing.Callable[[], T_Result], - google_ai_studio: typing.Callable[[], T_Result], - ) -> T_Result: - if self is LlmAdapter.ANTHROPIC: - return anthropic() - if self is LlmAdapter.OPEN_AI: - return open_ai() - if self is LlmAdapter.AZURE: - return azure() - if self is LlmAdapter.BEDROCK: - return bedrock() - if self is LlmAdapter.GOOGLE_VERTEX_AI: - return google_vertex_ai() - if self is LlmAdapter.GOOGLE_AI_STUDIO: - return google_ai_studio() diff --git a/langfuse/api/resources/llm_connections/types/llm_connection.py b/langfuse/api/resources/llm_connections/types/llm_connection.py deleted file mode 100644 index 6ded1459a..000000000 --- a/langfuse/api/resources/llm_connections/types/llm_connection.py +++ /dev/null @@ -1,92 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class LlmConnection(pydantic_v1.BaseModel): - """ - LLM API connection configuration (secrets excluded) - """ - - id: str - provider: str = pydantic_v1.Field() - """ - Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. - """ - - adapter: str = pydantic_v1.Field() - """ - The adapter used to interface with the LLM - """ - - display_secret_key: str = pydantic_v1.Field(alias="displaySecretKey") - """ - Masked version of the secret key for display purposes - """ - - base_url: typing.Optional[str] = pydantic_v1.Field(alias="baseURL", default=None) - """ - Custom base URL for the LLM API - """ - - custom_models: typing.List[str] = pydantic_v1.Field(alias="customModels") - """ - List of custom model names available for this connection - """ - - with_default_models: bool = pydantic_v1.Field(alias="withDefaultModels") - """ - Whether to include default models for this adapter - """ - - extra_header_keys: typing.List[str] = pydantic_v1.Field(alias="extraHeaderKeys") - """ - Keys of extra headers sent with requests (values excluded for security) - """ - - config: typing.Optional[typing.Dict[str, typing.Any]] = pydantic_v1.Field( - default=None - ) - """ - Adapter-specific configuration. Required for Bedrock (`{"region":"us-east-1"}`), optional for VertexAI (`{"location":"us-central1"}`), not used by other adapters. - """ - - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/llm_connections/types/paginated_llm_connections.py b/langfuse/api/resources/llm_connections/types/paginated_llm_connections.py deleted file mode 100644 index 986dbb0bb..000000000 --- a/langfuse/api/resources/llm_connections/types/paginated_llm_connections.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...utils.resources.pagination.types.meta_response import MetaResponse -from .llm_connection import LlmConnection - - -class PaginatedLlmConnections(pydantic_v1.BaseModel): - data: typing.List[LlmConnection] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/llm_connections/types/upsert_llm_connection_request.py b/langfuse/api/resources/llm_connections/types/upsert_llm_connection_request.py deleted file mode 100644 index 7490f25b7..000000000 --- a/langfuse/api/resources/llm_connections/types/upsert_llm_connection_request.py +++ /dev/null @@ -1,95 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .llm_adapter import LlmAdapter - - -class UpsertLlmConnectionRequest(pydantic_v1.BaseModel): - """ - Request to create or update an LLM connection (upsert) - """ - - provider: str = pydantic_v1.Field() - """ - Provider name (e.g., 'openai', 'my-gateway'). Must be unique in project, used for upserting. - """ - - adapter: LlmAdapter = pydantic_v1.Field() - """ - The adapter used to interface with the LLM - """ - - secret_key: str = pydantic_v1.Field(alias="secretKey") - """ - Secret key for the LLM API. - """ - - base_url: typing.Optional[str] = pydantic_v1.Field(alias="baseURL", default=None) - """ - Custom base URL for the LLM API - """ - - custom_models: typing.Optional[typing.List[str]] = pydantic_v1.Field( - alias="customModels", default=None - ) - """ - List of custom model names - """ - - with_default_models: typing.Optional[bool] = pydantic_v1.Field( - alias="withDefaultModels", default=None - ) - """ - Whether to include default models. Default is true. - """ - - extra_headers: typing.Optional[typing.Dict[str, str]] = pydantic_v1.Field( - alias="extraHeaders", default=None - ) - """ - Extra headers to send with requests - """ - - config: typing.Optional[typing.Dict[str, typing.Any]] = pydantic_v1.Field( - default=None - ) - """ - Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": ""}` (e.g., `{"region":"us-east-1"}`) - **VertexAI**: Optional. If provided, must be `{"location": ""}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/media/__init__.py b/langfuse/api/resources/media/__init__.py deleted file mode 100644 index f337d7a04..000000000 --- a/langfuse/api/resources/media/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - GetMediaResponse, - GetMediaUploadUrlRequest, - GetMediaUploadUrlResponse, - MediaContentType, - PatchMediaBody, -) - -__all__ = [ - "GetMediaResponse", - "GetMediaUploadUrlRequest", - "GetMediaUploadUrlResponse", - "MediaContentType", - "PatchMediaBody", -] diff --git a/langfuse/api/resources/media/client.py b/langfuse/api/resources/media/client.py deleted file mode 100644 index bb8e4b149..000000000 --- a/langfuse/api/resources/media/client.py +++ /dev/null @@ -1,505 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from .types.get_media_response import GetMediaResponse -from .types.get_media_upload_url_request import GetMediaUploadUrlRequest -from .types.get_media_upload_url_response import GetMediaUploadUrlResponse -from .types.patch_media_body import PatchMediaBody - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class MediaClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def get( - self, media_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> GetMediaResponse: - """ - Get a media record - - Parameters - ---------- - media_id : str - The unique langfuse identifier of a media record - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetMediaResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.media.get( - media_id="mediaId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/media/{jsonable_encoder(media_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(GetMediaResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def patch( - self, - media_id: str, - *, - request: PatchMediaBody, - request_options: typing.Optional[RequestOptions] = None, - ) -> None: - """ - Patch a media record - - Parameters - ---------- - media_id : str - The unique langfuse identifier of a media record - - request : PatchMediaBody - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import datetime - - from langfuse import PatchMediaBody - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.media.patch( - media_id="mediaId", - request=PatchMediaBody( - uploaded_at=datetime.datetime.fromisoformat( - "2024-01-15 09:30:00+00:00", - ), - upload_http_status=1, - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/media/{jsonable_encoder(media_id)}", - method="PATCH", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_upload_url( - self, - *, - request: GetMediaUploadUrlRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> GetMediaUploadUrlResponse: - """ - Get a presigned upload URL for a media record - - Parameters - ---------- - request : GetMediaUploadUrlRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetMediaUploadUrlResponse - - Examples - -------- - from langfuse import GetMediaUploadUrlRequest, MediaContentType - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.media.get_upload_url( - request=GetMediaUploadUrlRequest( - trace_id="traceId", - content_type=MediaContentType.IMAGE_PNG, - content_length=1, - sha_256_hash="sha256Hash", - field="field", - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/media", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - GetMediaUploadUrlResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncMediaClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def get( - self, media_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> GetMediaResponse: - """ - Get a media record - - Parameters - ---------- - media_id : str - The unique langfuse identifier of a media record - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetMediaResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.media.get( - media_id="mediaId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/media/{jsonable_encoder(media_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(GetMediaResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def patch( - self, - media_id: str, - *, - request: PatchMediaBody, - request_options: typing.Optional[RequestOptions] = None, - ) -> None: - """ - Patch a media record - - Parameters - ---------- - media_id : str - The unique langfuse identifier of a media record - - request : PatchMediaBody - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - import datetime - - from langfuse import PatchMediaBody - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.media.patch( - media_id="mediaId", - request=PatchMediaBody( - uploaded_at=datetime.datetime.fromisoformat( - "2024-01-15 09:30:00+00:00", - ), - upload_http_status=1, - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/media/{jsonable_encoder(media_id)}", - method="PATCH", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_upload_url( - self, - *, - request: GetMediaUploadUrlRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> GetMediaUploadUrlResponse: - """ - Get a presigned upload URL for a media record - - Parameters - ---------- - request : GetMediaUploadUrlRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - GetMediaUploadUrlResponse - - Examples - -------- - import asyncio - - from langfuse import GetMediaUploadUrlRequest, MediaContentType - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.media.get_upload_url( - request=GetMediaUploadUrlRequest( - trace_id="traceId", - content_type=MediaContentType.IMAGE_PNG, - content_length=1, - sha_256_hash="sha256Hash", - field="field", - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/media", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - GetMediaUploadUrlResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/media/types/__init__.py b/langfuse/api/resources/media/types/__init__.py deleted file mode 100644 index 20af676d8..000000000 --- a/langfuse/api/resources/media/types/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .get_media_response import GetMediaResponse -from .get_media_upload_url_request import GetMediaUploadUrlRequest -from .get_media_upload_url_response import GetMediaUploadUrlResponse -from .media_content_type import MediaContentType -from .patch_media_body import PatchMediaBody - -__all__ = [ - "GetMediaResponse", - "GetMediaUploadUrlRequest", - "GetMediaUploadUrlResponse", - "MediaContentType", - "PatchMediaBody", -] diff --git a/langfuse/api/resources/media/types/get_media_response.py b/langfuse/api/resources/media/types/get_media_response.py deleted file mode 100644 index fa5368872..000000000 --- a/langfuse/api/resources/media/types/get_media_response.py +++ /dev/null @@ -1,72 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class GetMediaResponse(pydantic_v1.BaseModel): - media_id: str = pydantic_v1.Field(alias="mediaId") - """ - The unique langfuse identifier of a media record - """ - - content_type: str = pydantic_v1.Field(alias="contentType") - """ - The MIME type of the media record - """ - - content_length: int = pydantic_v1.Field(alias="contentLength") - """ - The size of the media record in bytes - """ - - uploaded_at: dt.datetime = pydantic_v1.Field(alias="uploadedAt") - """ - The date and time when the media record was uploaded - """ - - url: str = pydantic_v1.Field() - """ - The download URL of the media record - """ - - url_expiry: str = pydantic_v1.Field(alias="urlExpiry") - """ - The expiry date and time of the media record download URL - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/media/types/get_media_upload_url_request.py b/langfuse/api/resources/media/types/get_media_upload_url_request.py deleted file mode 100644 index d0cde59fe..000000000 --- a/langfuse/api/resources/media/types/get_media_upload_url_request.py +++ /dev/null @@ -1,71 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .media_content_type import MediaContentType - - -class GetMediaUploadUrlRequest(pydantic_v1.BaseModel): - trace_id: str = pydantic_v1.Field(alias="traceId") - """ - The trace ID associated with the media record - """ - - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - """ - The observation ID associated with the media record. If the media record is associated directly with a trace, this will be null. - """ - - content_type: MediaContentType = pydantic_v1.Field(alias="contentType") - content_length: int = pydantic_v1.Field(alias="contentLength") - """ - The size of the media record in bytes - """ - - sha_256_hash: str = pydantic_v1.Field(alias="sha256Hash") - """ - The SHA-256 hash of the media record - """ - - field: str = pydantic_v1.Field() - """ - The trace / observation field the media record is associated with. This can be one of `input`, `output`, `metadata` - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/media/types/get_media_upload_url_response.py b/langfuse/api/resources/media/types/get_media_upload_url_response.py deleted file mode 100644 index fadc76c01..000000000 --- a/langfuse/api/resources/media/types/get_media_upload_url_response.py +++ /dev/null @@ -1,54 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class GetMediaUploadUrlResponse(pydantic_v1.BaseModel): - upload_url: typing.Optional[str] = pydantic_v1.Field( - alias="uploadUrl", default=None - ) - """ - The presigned upload URL. If the asset is already uploaded, this will be null - """ - - media_id: str = pydantic_v1.Field(alias="mediaId") - """ - The unique langfuse identifier of a media record - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/media/types/media_content_type.py b/langfuse/api/resources/media/types/media_content_type.py deleted file mode 100644 index 6942482bb..000000000 --- a/langfuse/api/resources/media/types/media_content_type.py +++ /dev/null @@ -1,231 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class MediaContentType(str, enum.Enum): - """ - The MIME type of the media record - """ - - IMAGE_PNG = "image/png" - IMAGE_JPEG = "image/jpeg" - IMAGE_JPG = "image/jpg" - IMAGE_WEBP = "image/webp" - IMAGE_GIF = "image/gif" - IMAGE_SVG_XML = "image/svg+xml" - IMAGE_TIFF = "image/tiff" - IMAGE_BMP = "image/bmp" - IMAGE_AVIF = "image/avif" - IMAGE_HEIC = "image/heic" - AUDIO_MPEG = "audio/mpeg" - AUDIO_MP_3 = "audio/mp3" - AUDIO_WAV = "audio/wav" - AUDIO_OGG = "audio/ogg" - AUDIO_OGA = "audio/oga" - AUDIO_AAC = "audio/aac" - AUDIO_MP_4 = "audio/mp4" - AUDIO_FLAC = "audio/flac" - AUDIO_OPUS = "audio/opus" - AUDIO_WEBM = "audio/webm" - VIDEO_MP_4 = "video/mp4" - VIDEO_WEBM = "video/webm" - VIDEO_OGG = "video/ogg" - VIDEO_MPEG = "video/mpeg" - VIDEO_QUICKTIME = "video/quicktime" - VIDEO_X_MSVIDEO = "video/x-msvideo" - VIDEO_X_MATROSKA = "video/x-matroska" - TEXT_PLAIN = "text/plain" - TEXT_HTML = "text/html" - TEXT_CSS = "text/css" - TEXT_CSV = "text/csv" - TEXT_MARKDOWN = "text/markdown" - TEXT_X_PYTHON = "text/x-python" - APPLICATION_JAVASCRIPT = "application/javascript" - TEXT_X_TYPESCRIPT = "text/x-typescript" - APPLICATION_X_YAML = "application/x-yaml" - APPLICATION_PDF = "application/pdf" - APPLICATION_MSWORD = "application/msword" - APPLICATION_MS_EXCEL = "application/vnd.ms-excel" - APPLICATION_OPENXML_SPREADSHEET = ( - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" - ) - APPLICATION_ZIP = "application/zip" - APPLICATION_JSON = "application/json" - APPLICATION_XML = "application/xml" - APPLICATION_OCTET_STREAM = "application/octet-stream" - APPLICATION_OPENXML_WORD = ( - "application/vnd.openxmlformats-officedocument.wordprocessingml.document" - ) - APPLICATION_OPENXML_PRESENTATION = ( - "application/vnd.openxmlformats-officedocument.presentationml.presentation" - ) - APPLICATION_RTF = "application/rtf" - APPLICATION_X_NDJSON = "application/x-ndjson" - APPLICATION_PARQUET = "application/vnd.apache.parquet" - APPLICATION_GZIP = "application/gzip" - APPLICATION_X_TAR = "application/x-tar" - APPLICATION_X_7_Z_COMPRESSED = "application/x-7z-compressed" - - def visit( - self, - image_png: typing.Callable[[], T_Result], - image_jpeg: typing.Callable[[], T_Result], - image_jpg: typing.Callable[[], T_Result], - image_webp: typing.Callable[[], T_Result], - image_gif: typing.Callable[[], T_Result], - image_svg_xml: typing.Callable[[], T_Result], - image_tiff: typing.Callable[[], T_Result], - image_bmp: typing.Callable[[], T_Result], - image_avif: typing.Callable[[], T_Result], - image_heic: typing.Callable[[], T_Result], - audio_mpeg: typing.Callable[[], T_Result], - audio_mp_3: typing.Callable[[], T_Result], - audio_wav: typing.Callable[[], T_Result], - audio_ogg: typing.Callable[[], T_Result], - audio_oga: typing.Callable[[], T_Result], - audio_aac: typing.Callable[[], T_Result], - audio_mp_4: typing.Callable[[], T_Result], - audio_flac: typing.Callable[[], T_Result], - audio_opus: typing.Callable[[], T_Result], - audio_webm: typing.Callable[[], T_Result], - video_mp_4: typing.Callable[[], T_Result], - video_webm: typing.Callable[[], T_Result], - video_ogg: typing.Callable[[], T_Result], - video_mpeg: typing.Callable[[], T_Result], - video_quicktime: typing.Callable[[], T_Result], - video_x_msvideo: typing.Callable[[], T_Result], - video_x_matroska: typing.Callable[[], T_Result], - text_plain: typing.Callable[[], T_Result], - text_html: typing.Callable[[], T_Result], - text_css: typing.Callable[[], T_Result], - text_csv: typing.Callable[[], T_Result], - text_markdown: typing.Callable[[], T_Result], - text_x_python: typing.Callable[[], T_Result], - application_javascript: typing.Callable[[], T_Result], - text_x_typescript: typing.Callable[[], T_Result], - application_x_yaml: typing.Callable[[], T_Result], - application_pdf: typing.Callable[[], T_Result], - application_msword: typing.Callable[[], T_Result], - application_ms_excel: typing.Callable[[], T_Result], - application_openxml_spreadsheet: typing.Callable[[], T_Result], - application_zip: typing.Callable[[], T_Result], - application_json: typing.Callable[[], T_Result], - application_xml: typing.Callable[[], T_Result], - application_octet_stream: typing.Callable[[], T_Result], - application_openxml_word: typing.Callable[[], T_Result], - application_openxml_presentation: typing.Callable[[], T_Result], - application_rtf: typing.Callable[[], T_Result], - application_x_ndjson: typing.Callable[[], T_Result], - application_parquet: typing.Callable[[], T_Result], - application_gzip: typing.Callable[[], T_Result], - application_x_tar: typing.Callable[[], T_Result], - application_x_7_z_compressed: typing.Callable[[], T_Result], - ) -> T_Result: - if self is MediaContentType.IMAGE_PNG: - return image_png() - if self is MediaContentType.IMAGE_JPEG: - return image_jpeg() - if self is MediaContentType.IMAGE_JPG: - return image_jpg() - if self is MediaContentType.IMAGE_WEBP: - return image_webp() - if self is MediaContentType.IMAGE_GIF: - return image_gif() - if self is MediaContentType.IMAGE_SVG_XML: - return image_svg_xml() - if self is MediaContentType.IMAGE_TIFF: - return image_tiff() - if self is MediaContentType.IMAGE_BMP: - return image_bmp() - if self is MediaContentType.IMAGE_AVIF: - return image_avif() - if self is MediaContentType.IMAGE_HEIC: - return image_heic() - if self is MediaContentType.AUDIO_MPEG: - return audio_mpeg() - if self is MediaContentType.AUDIO_MP_3: - return audio_mp_3() - if self is MediaContentType.AUDIO_WAV: - return audio_wav() - if self is MediaContentType.AUDIO_OGG: - return audio_ogg() - if self is MediaContentType.AUDIO_OGA: - return audio_oga() - if self is MediaContentType.AUDIO_AAC: - return audio_aac() - if self is MediaContentType.AUDIO_MP_4: - return audio_mp_4() - if self is MediaContentType.AUDIO_FLAC: - return audio_flac() - if self is MediaContentType.AUDIO_OPUS: - return audio_opus() - if self is MediaContentType.AUDIO_WEBM: - return audio_webm() - if self is MediaContentType.VIDEO_MP_4: - return video_mp_4() - if self is MediaContentType.VIDEO_WEBM: - return video_webm() - if self is MediaContentType.VIDEO_OGG: - return video_ogg() - if self is MediaContentType.VIDEO_MPEG: - return video_mpeg() - if self is MediaContentType.VIDEO_QUICKTIME: - return video_quicktime() - if self is MediaContentType.VIDEO_X_MSVIDEO: - return video_x_msvideo() - if self is MediaContentType.VIDEO_X_MATROSKA: - return video_x_matroska() - if self is MediaContentType.TEXT_PLAIN: - return text_plain() - if self is MediaContentType.TEXT_HTML: - return text_html() - if self is MediaContentType.TEXT_CSS: - return text_css() - if self is MediaContentType.TEXT_CSV: - return text_csv() - if self is MediaContentType.TEXT_MARKDOWN: - return text_markdown() - if self is MediaContentType.TEXT_X_PYTHON: - return text_x_python() - if self is MediaContentType.APPLICATION_JAVASCRIPT: - return application_javascript() - if self is MediaContentType.TEXT_X_TYPESCRIPT: - return text_x_typescript() - if self is MediaContentType.APPLICATION_X_YAML: - return application_x_yaml() - if self is MediaContentType.APPLICATION_PDF: - return application_pdf() - if self is MediaContentType.APPLICATION_MSWORD: - return application_msword() - if self is MediaContentType.APPLICATION_MS_EXCEL: - return application_ms_excel() - if self is MediaContentType.APPLICATION_OPENXML_SPREADSHEET: - return application_openxml_spreadsheet() - if self is MediaContentType.APPLICATION_ZIP: - return application_zip() - if self is MediaContentType.APPLICATION_JSON: - return application_json() - if self is MediaContentType.APPLICATION_XML: - return application_xml() - if self is MediaContentType.APPLICATION_OCTET_STREAM: - return application_octet_stream() - if self is MediaContentType.APPLICATION_OPENXML_WORD: - return application_openxml_word() - if self is MediaContentType.APPLICATION_OPENXML_PRESENTATION: - return application_openxml_presentation() - if self is MediaContentType.APPLICATION_RTF: - return application_rtf() - if self is MediaContentType.APPLICATION_X_NDJSON: - return application_x_ndjson() - if self is MediaContentType.APPLICATION_PARQUET: - return application_parquet() - if self is MediaContentType.APPLICATION_GZIP: - return application_gzip() - if self is MediaContentType.APPLICATION_X_TAR: - return application_x_tar() - if self is MediaContentType.APPLICATION_X_7_Z_COMPRESSED: - return application_x_7_z_compressed() diff --git a/langfuse/api/resources/media/types/patch_media_body.py b/langfuse/api/resources/media/types/patch_media_body.py deleted file mode 100644 index 49f0c3432..000000000 --- a/langfuse/api/resources/media/types/patch_media_body.py +++ /dev/null @@ -1,66 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class PatchMediaBody(pydantic_v1.BaseModel): - uploaded_at: dt.datetime = pydantic_v1.Field(alias="uploadedAt") - """ - The date and time when the media record was uploaded - """ - - upload_http_status: int = pydantic_v1.Field(alias="uploadHttpStatus") - """ - The HTTP status code of the upload - """ - - upload_http_error: typing.Optional[str] = pydantic_v1.Field( - alias="uploadHttpError", default=None - ) - """ - The HTTP error message of the upload - """ - - upload_time_ms: typing.Optional[int] = pydantic_v1.Field( - alias="uploadTimeMs", default=None - ) - """ - The time in milliseconds it took to upload the media record - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/metrics/__init__.py b/langfuse/api/resources/metrics/__init__.py deleted file mode 100644 index 90e510b5f..000000000 --- a/langfuse/api/resources/metrics/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import MetricsResponse - -__all__ = ["MetricsResponse"] diff --git a/langfuse/api/resources/metrics/types/__init__.py b/langfuse/api/resources/metrics/types/__init__.py deleted file mode 100644 index 7bf03027d..000000000 --- a/langfuse/api/resources/metrics/types/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .metrics_response import MetricsResponse - -__all__ = ["MetricsResponse"] diff --git a/langfuse/api/resources/metrics/types/metrics_response.py b/langfuse/api/resources/metrics/types/metrics_response.py deleted file mode 100644 index af0121c84..000000000 --- a/langfuse/api/resources/metrics/types/metrics_response.py +++ /dev/null @@ -1,47 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class MetricsResponse(pydantic_v1.BaseModel): - data: typing.List[typing.Dict[str, typing.Any]] = pydantic_v1.Field() - """ - The metrics data. Each item in the list contains the metric values and dimensions requested in the query. - Format varies based on the query parameters. - Histograms will return an array with [lower, upper, height] tuples. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/models/__init__.py b/langfuse/api/resources/models/__init__.py deleted file mode 100644 index a41fff3e5..000000000 --- a/langfuse/api/resources/models/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import CreateModelRequest, PaginatedModels - -__all__ = ["CreateModelRequest", "PaginatedModels"] diff --git a/langfuse/api/resources/models/client.py b/langfuse/api/resources/models/client.py deleted file mode 100644 index 4f4b727fa..000000000 --- a/langfuse/api/resources/models/client.py +++ /dev/null @@ -1,607 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from ..commons.types.model import Model -from .types.create_model_request import CreateModelRequest -from .types.paginated_models import PaginatedModels - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class ModelsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def create( - self, - *, - request: CreateModelRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> Model: - """ - Create a model - - Parameters - ---------- - request : CreateModelRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Model - - Examples - -------- - from langfuse import CreateModelRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.models.create( - request=CreateModelRequest( - model_name="modelName", - match_pattern="matchPattern", - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/models", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Model, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedModels: - """ - Get all models - - Parameters - ---------- - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedModels - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.models.list() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/models", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(PaginatedModels, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> Model: - """ - Get a model - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Model - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.models.get( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/models/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Model, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Delete a model. Cannot delete models managed by Langfuse. You can create your own definition with the same modelName to override the definition though. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.models.delete( - id="id", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/models/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncModelsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def create( - self, - *, - request: CreateModelRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> Model: - """ - Create a model - - Parameters - ---------- - request : CreateModelRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Model - - Examples - -------- - import asyncio - - from langfuse import CreateModelRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.models.create( - request=CreateModelRequest( - model_name="modelName", - match_pattern="matchPattern", - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/models", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Model, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedModels: - """ - Get all models - - Parameters - ---------- - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedModels - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.models.list() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/models", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(PaginatedModels, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> Model: - """ - Get a model - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Model - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.models.get( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/models/{jsonable_encoder(id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Model, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete( - self, id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Delete a model. Cannot delete models managed by Langfuse. You can create your own definition with the same modelName to override the definition though. - - Parameters - ---------- - id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.models.delete( - id="id", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/models/{jsonable_encoder(id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/models/types/__init__.py b/langfuse/api/resources/models/types/__init__.py deleted file mode 100644 index 94285af35..000000000 --- a/langfuse/api/resources/models/types/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .create_model_request import CreateModelRequest -from .paginated_models import PaginatedModels - -__all__ = ["CreateModelRequest", "PaginatedModels"] diff --git a/langfuse/api/resources/models/types/paginated_models.py b/langfuse/api/resources/models/types/paginated_models.py deleted file mode 100644 index 3469a1fe6..000000000 --- a/langfuse/api/resources/models/types/paginated_models.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.model import Model -from ...utils.resources.pagination.types.meta_response import MetaResponse - - -class PaginatedModels(pydantic_v1.BaseModel): - data: typing.List[Model] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/observations/__init__.py b/langfuse/api/resources/observations/__init__.py deleted file mode 100644 index 95fd7c721..000000000 --- a/langfuse/api/resources/observations/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import Observations, ObservationsViews - -__all__ = ["Observations", "ObservationsViews"] diff --git a/langfuse/api/resources/observations/types/__init__.py b/langfuse/api/resources/observations/types/__init__.py deleted file mode 100644 index 60f9d4e01..000000000 --- a/langfuse/api/resources/observations/types/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .observations import Observations -from .observations_views import ObservationsViews - -__all__ = ["Observations", "ObservationsViews"] diff --git a/langfuse/api/resources/observations/types/observations.py b/langfuse/api/resources/observations/types/observations.py deleted file mode 100644 index 1534dc87e..000000000 --- a/langfuse/api/resources/observations/types/observations.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.observation import Observation -from ...utils.resources.pagination.types.meta_response import MetaResponse - - -class Observations(pydantic_v1.BaseModel): - data: typing.List[Observation] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/observations/types/observations_views.py b/langfuse/api/resources/observations/types/observations_views.py deleted file mode 100644 index ed86b7d1e..000000000 --- a/langfuse/api/resources/observations/types/observations_views.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.observations_view import ObservationsView -from ...utils.resources.pagination.types.meta_response import MetaResponse - - -class ObservationsViews(pydantic_v1.BaseModel): - data: typing.List[ObservationsView] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/opentelemetry/__init__.py b/langfuse/api/resources/opentelemetry/__init__.py deleted file mode 100644 index bada2052f..000000000 --- a/langfuse/api/resources/opentelemetry/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - OtelAttribute, - OtelAttributeValue, - OtelResource, - OtelResourceSpan, - OtelScope, - OtelScopeSpan, - OtelSpan, - OtelTraceResponse, -) - -__all__ = [ - "OtelAttribute", - "OtelAttributeValue", - "OtelResource", - "OtelResourceSpan", - "OtelScope", - "OtelScopeSpan", - "OtelSpan", - "OtelTraceResponse", -] diff --git a/langfuse/api/resources/opentelemetry/types/__init__.py b/langfuse/api/resources/opentelemetry/types/__init__.py deleted file mode 100644 index 4ca603db6..000000000 --- a/langfuse/api/resources/opentelemetry/types/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .otel_attribute import OtelAttribute -from .otel_attribute_value import OtelAttributeValue -from .otel_resource import OtelResource -from .otel_resource_span import OtelResourceSpan -from .otel_scope import OtelScope -from .otel_scope_span import OtelScopeSpan -from .otel_span import OtelSpan -from .otel_trace_response import OtelTraceResponse - -__all__ = [ - "OtelAttribute", - "OtelAttributeValue", - "OtelResource", - "OtelResourceSpan", - "OtelScope", - "OtelScopeSpan", - "OtelSpan", - "OtelTraceResponse", -] diff --git a/langfuse/api/resources/opentelemetry/types/otel_attribute.py b/langfuse/api/resources/opentelemetry/types/otel_attribute.py deleted file mode 100644 index 91b9e2b70..000000000 --- a/langfuse/api/resources/opentelemetry/types/otel_attribute.py +++ /dev/null @@ -1,55 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .otel_attribute_value import OtelAttributeValue - - -class OtelAttribute(pydantic_v1.BaseModel): - """ - Key-value attribute pair for resources, scopes, or spans - """ - - key: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - Attribute key (e.g., "service.name", "langfuse.observation.type") - """ - - value: typing.Optional[OtelAttributeValue] = pydantic_v1.Field(default=None) - """ - Attribute value - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/opentelemetry/types/otel_attribute_value.py b/langfuse/api/resources/opentelemetry/types/otel_attribute_value.py deleted file mode 100644 index 51f026495..000000000 --- a/langfuse/api/resources/opentelemetry/types/otel_attribute_value.py +++ /dev/null @@ -1,72 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class OtelAttributeValue(pydantic_v1.BaseModel): - """ - Attribute value wrapper supporting different value types - """ - - string_value: typing.Optional[str] = pydantic_v1.Field( - alias="stringValue", default=None - ) - """ - String value - """ - - int_value: typing.Optional[int] = pydantic_v1.Field(alias="intValue", default=None) - """ - Integer value - """ - - double_value: typing.Optional[float] = pydantic_v1.Field( - alias="doubleValue", default=None - ) - """ - Double value - """ - - bool_value: typing.Optional[bool] = pydantic_v1.Field( - alias="boolValue", default=None - ) - """ - Boolean value - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/opentelemetry/types/otel_resource.py b/langfuse/api/resources/opentelemetry/types/otel_resource.py deleted file mode 100644 index 0d76d5a15..000000000 --- a/langfuse/api/resources/opentelemetry/types/otel_resource.py +++ /dev/null @@ -1,52 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .otel_attribute import OtelAttribute - - -class OtelResource(pydantic_v1.BaseModel): - """ - Resource attributes identifying the source of telemetry - """ - - attributes: typing.Optional[typing.List[OtelAttribute]] = pydantic_v1.Field( - default=None - ) - """ - Resource attributes like service.name, service.version, etc. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/opentelemetry/types/otel_resource_span.py b/langfuse/api/resources/opentelemetry/types/otel_resource_span.py deleted file mode 100644 index e270ba7d8..000000000 --- a/langfuse/api/resources/opentelemetry/types/otel_resource_span.py +++ /dev/null @@ -1,60 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .otel_resource import OtelResource -from .otel_scope_span import OtelScopeSpan - - -class OtelResourceSpan(pydantic_v1.BaseModel): - """ - Represents a collection of spans from a single resource as per OTLP specification - """ - - resource: typing.Optional[OtelResource] = pydantic_v1.Field(default=None) - """ - Resource information - """ - - scope_spans: typing.Optional[typing.List[OtelScopeSpan]] = pydantic_v1.Field( - alias="scopeSpans", default=None - ) - """ - Array of scope spans - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/opentelemetry/types/otel_scope.py b/langfuse/api/resources/opentelemetry/types/otel_scope.py deleted file mode 100644 index 71e9b75b8..000000000 --- a/langfuse/api/resources/opentelemetry/types/otel_scope.py +++ /dev/null @@ -1,62 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .otel_attribute import OtelAttribute - - -class OtelScope(pydantic_v1.BaseModel): - """ - Instrumentation scope information - """ - - name: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - Instrumentation scope name - """ - - version: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - Instrumentation scope version - """ - - attributes: typing.Optional[typing.List[OtelAttribute]] = pydantic_v1.Field( - default=None - ) - """ - Additional scope attributes - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/opentelemetry/types/otel_scope_span.py b/langfuse/api/resources/opentelemetry/types/otel_scope_span.py deleted file mode 100644 index 854951a60..000000000 --- a/langfuse/api/resources/opentelemetry/types/otel_scope_span.py +++ /dev/null @@ -1,56 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .otel_scope import OtelScope -from .otel_span import OtelSpan - - -class OtelScopeSpan(pydantic_v1.BaseModel): - """ - Collection of spans from a single instrumentation scope - """ - - scope: typing.Optional[OtelScope] = pydantic_v1.Field(default=None) - """ - Instrumentation scope information - """ - - spans: typing.Optional[typing.List[OtelSpan]] = pydantic_v1.Field(default=None) - """ - Array of spans - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/opentelemetry/types/otel_span.py b/langfuse/api/resources/opentelemetry/types/otel_span.py deleted file mode 100644 index 08b7be7fb..000000000 --- a/langfuse/api/resources/opentelemetry/types/otel_span.py +++ /dev/null @@ -1,104 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .otel_attribute import OtelAttribute - - -class OtelSpan(pydantic_v1.BaseModel): - """ - Individual span representing a unit of work or operation - """ - - trace_id: typing.Optional[typing.Any] = pydantic_v1.Field( - alias="traceId", default=None - ) - """ - Trace ID (16 bytes, hex-encoded string in JSON or Buffer in binary) - """ - - span_id: typing.Optional[typing.Any] = pydantic_v1.Field( - alias="spanId", default=None - ) - """ - Span ID (8 bytes, hex-encoded string in JSON or Buffer in binary) - """ - - parent_span_id: typing.Optional[typing.Any] = pydantic_v1.Field( - alias="parentSpanId", default=None - ) - """ - Parent span ID if this is a child span - """ - - name: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - Span name describing the operation - """ - - kind: typing.Optional[int] = pydantic_v1.Field(default=None) - """ - Span kind (1=INTERNAL, 2=SERVER, 3=CLIENT, 4=PRODUCER, 5=CONSUMER) - """ - - start_time_unix_nano: typing.Optional[typing.Any] = pydantic_v1.Field( - alias="startTimeUnixNano", default=None - ) - """ - Start time in nanoseconds since Unix epoch - """ - - end_time_unix_nano: typing.Optional[typing.Any] = pydantic_v1.Field( - alias="endTimeUnixNano", default=None - ) - """ - End time in nanoseconds since Unix epoch - """ - - attributes: typing.Optional[typing.List[OtelAttribute]] = pydantic_v1.Field( - default=None - ) - """ - Span attributes including Langfuse-specific attributes (langfuse.observation.*) - """ - - status: typing.Optional[typing.Any] = pydantic_v1.Field(default=None) - """ - Span status object - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/opentelemetry/types/otel_trace_response.py b/langfuse/api/resources/opentelemetry/types/otel_trace_response.py deleted file mode 100644 index ef9897f06..000000000 --- a/langfuse/api/resources/opentelemetry/types/otel_trace_response.py +++ /dev/null @@ -1,44 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class OtelTraceResponse(pydantic_v1.BaseModel): - """ - Response from trace export request. Empty object indicates success. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/organizations/__init__.py b/langfuse/api/resources/organizations/__init__.py deleted file mode 100644 index 36249ae36..000000000 --- a/langfuse/api/resources/organizations/__init__.py +++ /dev/null @@ -1,27 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - DeleteMembershipRequest, - MembershipDeletionResponse, - MembershipRequest, - MembershipResponse, - MembershipRole, - MembershipsResponse, - OrganizationApiKey, - OrganizationApiKeysResponse, - OrganizationProject, - OrganizationProjectsResponse, -) - -__all__ = [ - "DeleteMembershipRequest", - "MembershipDeletionResponse", - "MembershipRequest", - "MembershipResponse", - "MembershipRole", - "MembershipsResponse", - "OrganizationApiKey", - "OrganizationApiKeysResponse", - "OrganizationProject", - "OrganizationProjectsResponse", -] diff --git a/langfuse/api/resources/organizations/client.py b/langfuse/api/resources/organizations/client.py deleted file mode 100644 index 1e7bcd117..000000000 --- a/langfuse/api/resources/organizations/client.py +++ /dev/null @@ -1,1205 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from .types.delete_membership_request import DeleteMembershipRequest -from .types.membership_deletion_response import MembershipDeletionResponse -from .types.membership_request import MembershipRequest -from .types.membership_response import MembershipResponse -from .types.memberships_response import MembershipsResponse -from .types.organization_api_keys_response import OrganizationApiKeysResponse -from .types.organization_projects_response import OrganizationProjectsResponse - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class OrganizationsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def get_organization_memberships( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> MembershipsResponse: - """ - Get all memberships for the organization associated with the API key (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipsResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.organizations.get_organization_memberships() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/organizations/memberships", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(MembershipsResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def update_organization_membership( - self, - *, - request: MembershipRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> MembershipResponse: - """ - Create or update a membership for the organization associated with the API key (requires organization-scoped API key) - - Parameters - ---------- - request : MembershipRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipResponse - - Examples - -------- - from langfuse import MembershipRequest, MembershipRole - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.organizations.update_organization_membership( - request=MembershipRequest( - user_id="userId", - role=MembershipRole.OWNER, - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/organizations/memberships", - method="PUT", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(MembershipResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete_organization_membership( - self, - *, - request: DeleteMembershipRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> MembershipDeletionResponse: - """ - Delete a membership from the organization associated with the API key (requires organization-scoped API key) - - Parameters - ---------- - request : DeleteMembershipRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipDeletionResponse - - Examples - -------- - from langfuse import DeleteMembershipRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.organizations.delete_organization_membership( - request=DeleteMembershipRequest( - user_id="userId", - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/organizations/memberships", - method="DELETE", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - MembershipDeletionResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_project_memberships( - self, - project_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> MembershipsResponse: - """ - Get all memberships for a specific project (requires organization-scoped API key) - - Parameters - ---------- - project_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipsResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.organizations.get_project_memberships( - project_id="projectId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/memberships", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(MembershipsResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def update_project_membership( - self, - project_id: str, - *, - request: MembershipRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> MembershipResponse: - """ - Create or update a membership for a specific project (requires organization-scoped API key). The user must already be a member of the organization. - - Parameters - ---------- - project_id : str - - request : MembershipRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipResponse - - Examples - -------- - from langfuse import MembershipRequest, MembershipRole - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.organizations.update_project_membership( - project_id="projectId", - request=MembershipRequest( - user_id="userId", - role=MembershipRole.OWNER, - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/memberships", - method="PUT", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(MembershipResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete_project_membership( - self, - project_id: str, - *, - request: DeleteMembershipRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> MembershipDeletionResponse: - """ - Delete a membership from a specific project (requires organization-scoped API key). The user must be a member of the organization. - - Parameters - ---------- - project_id : str - - request : DeleteMembershipRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipDeletionResponse - - Examples - -------- - from langfuse import DeleteMembershipRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.organizations.delete_project_membership( - project_id="projectId", - request=DeleteMembershipRequest( - user_id="userId", - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/memberships", - method="DELETE", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - MembershipDeletionResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_organization_projects( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> OrganizationProjectsResponse: - """ - Get all projects for the organization associated with the API key (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationProjectsResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.organizations.get_organization_projects() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/organizations/projects", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - OrganizationProjectsResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_organization_api_keys( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> OrganizationApiKeysResponse: - """ - Get all API keys for the organization associated with the API key (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationApiKeysResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.organizations.get_organization_api_keys() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/organizations/apiKeys", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - OrganizationApiKeysResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncOrganizationsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def get_organization_memberships( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> MembershipsResponse: - """ - Get all memberships for the organization associated with the API key (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipsResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.organizations.get_organization_memberships() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/organizations/memberships", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(MembershipsResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def update_organization_membership( - self, - *, - request: MembershipRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> MembershipResponse: - """ - Create or update a membership for the organization associated with the API key (requires organization-scoped API key) - - Parameters - ---------- - request : MembershipRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipResponse - - Examples - -------- - import asyncio - - from langfuse import MembershipRequest, MembershipRole - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.organizations.update_organization_membership( - request=MembershipRequest( - user_id="userId", - role=MembershipRole.OWNER, - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/organizations/memberships", - method="PUT", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(MembershipResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete_organization_membership( - self, - *, - request: DeleteMembershipRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> MembershipDeletionResponse: - """ - Delete a membership from the organization associated with the API key (requires organization-scoped API key) - - Parameters - ---------- - request : DeleteMembershipRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipDeletionResponse - - Examples - -------- - import asyncio - - from langfuse import DeleteMembershipRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.organizations.delete_organization_membership( - request=DeleteMembershipRequest( - user_id="userId", - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/organizations/memberships", - method="DELETE", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - MembershipDeletionResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_project_memberships( - self, - project_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> MembershipsResponse: - """ - Get all memberships for a specific project (requires organization-scoped API key) - - Parameters - ---------- - project_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipsResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.organizations.get_project_memberships( - project_id="projectId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/memberships", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(MembershipsResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def update_project_membership( - self, - project_id: str, - *, - request: MembershipRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> MembershipResponse: - """ - Create or update a membership for a specific project (requires organization-scoped API key). The user must already be a member of the organization. - - Parameters - ---------- - project_id : str - - request : MembershipRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipResponse - - Examples - -------- - import asyncio - - from langfuse import MembershipRequest, MembershipRole - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.organizations.update_project_membership( - project_id="projectId", - request=MembershipRequest( - user_id="userId", - role=MembershipRole.OWNER, - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/memberships", - method="PUT", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(MembershipResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete_project_membership( - self, - project_id: str, - *, - request: DeleteMembershipRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> MembershipDeletionResponse: - """ - Delete a membership from a specific project (requires organization-scoped API key). The user must be a member of the organization. - - Parameters - ---------- - project_id : str - - request : DeleteMembershipRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - MembershipDeletionResponse - - Examples - -------- - import asyncio - - from langfuse import DeleteMembershipRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.organizations.delete_project_membership( - project_id="projectId", - request=DeleteMembershipRequest( - user_id="userId", - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/memberships", - method="DELETE", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - MembershipDeletionResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_organization_projects( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> OrganizationProjectsResponse: - """ - Get all projects for the organization associated with the API key (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationProjectsResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.organizations.get_organization_projects() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/organizations/projects", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - OrganizationProjectsResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_organization_api_keys( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> OrganizationApiKeysResponse: - """ - Get all API keys for the organization associated with the API key (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - OrganizationApiKeysResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.organizations.get_organization_api_keys() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/organizations/apiKeys", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - OrganizationApiKeysResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/organizations/types/__init__.py b/langfuse/api/resources/organizations/types/__init__.py deleted file mode 100644 index b3ea09797..000000000 --- a/langfuse/api/resources/organizations/types/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .delete_membership_request import DeleteMembershipRequest -from .membership_deletion_response import MembershipDeletionResponse -from .membership_request import MembershipRequest -from .membership_response import MembershipResponse -from .membership_role import MembershipRole -from .memberships_response import MembershipsResponse -from .organization_api_key import OrganizationApiKey -from .organization_api_keys_response import OrganizationApiKeysResponse -from .organization_project import OrganizationProject -from .organization_projects_response import OrganizationProjectsResponse - -__all__ = [ - "DeleteMembershipRequest", - "MembershipDeletionResponse", - "MembershipRequest", - "MembershipResponse", - "MembershipRole", - "MembershipsResponse", - "OrganizationApiKey", - "OrganizationApiKeysResponse", - "OrganizationProject", - "OrganizationProjectsResponse", -] diff --git a/langfuse/api/resources/organizations/types/delete_membership_request.py b/langfuse/api/resources/organizations/types/delete_membership_request.py deleted file mode 100644 index 6752b0aae..000000000 --- a/langfuse/api/resources/organizations/types/delete_membership_request.py +++ /dev/null @@ -1,44 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class DeleteMembershipRequest(pydantic_v1.BaseModel): - user_id: str = pydantic_v1.Field(alias="userId") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/organizations/types/membership_deletion_response.py b/langfuse/api/resources/organizations/types/membership_deletion_response.py deleted file mode 100644 index f9c1915b7..000000000 --- a/langfuse/api/resources/organizations/types/membership_deletion_response.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class MembershipDeletionResponse(pydantic_v1.BaseModel): - message: str - user_id: str = pydantic_v1.Field(alias="userId") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/organizations/types/membership_request.py b/langfuse/api/resources/organizations/types/membership_request.py deleted file mode 100644 index a7f046f51..000000000 --- a/langfuse/api/resources/organizations/types/membership_request.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .membership_role import MembershipRole - - -class MembershipRequest(pydantic_v1.BaseModel): - user_id: str = pydantic_v1.Field(alias="userId") - role: MembershipRole - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/organizations/types/membership_response.py b/langfuse/api/resources/organizations/types/membership_response.py deleted file mode 100644 index e9d82f3c7..000000000 --- a/langfuse/api/resources/organizations/types/membership_response.py +++ /dev/null @@ -1,48 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .membership_role import MembershipRole - - -class MembershipResponse(pydantic_v1.BaseModel): - user_id: str = pydantic_v1.Field(alias="userId") - role: MembershipRole - email: str - name: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/organizations/types/membership_role.py b/langfuse/api/resources/organizations/types/membership_role.py deleted file mode 100644 index 1721cc0ed..000000000 --- a/langfuse/api/resources/organizations/types/membership_role.py +++ /dev/null @@ -1,29 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class MembershipRole(str, enum.Enum): - OWNER = "OWNER" - ADMIN = "ADMIN" - MEMBER = "MEMBER" - VIEWER = "VIEWER" - - def visit( - self, - owner: typing.Callable[[], T_Result], - admin: typing.Callable[[], T_Result], - member: typing.Callable[[], T_Result], - viewer: typing.Callable[[], T_Result], - ) -> T_Result: - if self is MembershipRole.OWNER: - return owner() - if self is MembershipRole.ADMIN: - return admin() - if self is MembershipRole.MEMBER: - return member() - if self is MembershipRole.VIEWER: - return viewer() diff --git a/langfuse/api/resources/organizations/types/memberships_response.py b/langfuse/api/resources/organizations/types/memberships_response.py deleted file mode 100644 index 0a8091449..000000000 --- a/langfuse/api/resources/organizations/types/memberships_response.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .membership_response import MembershipResponse - - -class MembershipsResponse(pydantic_v1.BaseModel): - memberships: typing.List[MembershipResponse] - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/organizations/types/organization_api_key.py b/langfuse/api/resources/organizations/types/organization_api_key.py deleted file mode 100644 index ad54bb182..000000000 --- a/langfuse/api/resources/organizations/types/organization_api_key.py +++ /dev/null @@ -1,54 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class OrganizationApiKey(pydantic_v1.BaseModel): - id: str - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - expires_at: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="expiresAt", default=None - ) - last_used_at: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="lastUsedAt", default=None - ) - note: typing.Optional[str] = None - public_key: str = pydantic_v1.Field(alias="publicKey") - display_secret_key: str = pydantic_v1.Field(alias="displaySecretKey") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/organizations/types/organization_api_keys_response.py b/langfuse/api/resources/organizations/types/organization_api_keys_response.py deleted file mode 100644 index e19ce6373..000000000 --- a/langfuse/api/resources/organizations/types/organization_api_keys_response.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .organization_api_key import OrganizationApiKey - - -class OrganizationApiKeysResponse(pydantic_v1.BaseModel): - api_keys: typing.List[OrganizationApiKey] = pydantic_v1.Field(alias="apiKeys") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/organizations/types/organization_project.py b/langfuse/api/resources/organizations/types/organization_project.py deleted file mode 100644 index 87f245b9a..000000000 --- a/langfuse/api/resources/organizations/types/organization_project.py +++ /dev/null @@ -1,48 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class OrganizationProject(pydantic_v1.BaseModel): - id: str - name: str - metadata: typing.Optional[typing.Dict[str, typing.Any]] = None - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/organizations/types/organization_projects_response.py b/langfuse/api/resources/organizations/types/organization_projects_response.py deleted file mode 100644 index 1c939a3e0..000000000 --- a/langfuse/api/resources/organizations/types/organization_projects_response.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .organization_project import OrganizationProject - - -class OrganizationProjectsResponse(pydantic_v1.BaseModel): - projects: typing.List[OrganizationProject] - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/projects/__init__.py b/langfuse/api/resources/projects/__init__.py deleted file mode 100644 index 26c74c1c7..000000000 --- a/langfuse/api/resources/projects/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - ApiKeyDeletionResponse, - ApiKeyList, - ApiKeyResponse, - ApiKeySummary, - Project, - ProjectDeletionResponse, - Projects, -) - -__all__ = [ - "ApiKeyDeletionResponse", - "ApiKeyList", - "ApiKeyResponse", - "ApiKeySummary", - "Project", - "ProjectDeletionResponse", - "Projects", -] diff --git a/langfuse/api/resources/projects/client.py b/langfuse/api/resources/projects/client.py deleted file mode 100644 index 5af232dfb..000000000 --- a/langfuse/api/resources/projects/client.py +++ /dev/null @@ -1,1106 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from .types.api_key_deletion_response import ApiKeyDeletionResponse -from .types.api_key_list import ApiKeyList -from .types.api_key_response import ApiKeyResponse -from .types.project import Project -from .types.project_deletion_response import ProjectDeletionResponse -from .types.projects import Projects - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class ProjectsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def get( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> Projects: - """ - Get Project associated with API key (requires project-scoped API key). You can use GET /api/public/organizations/projects to get all projects with an organization-scoped key. - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Projects - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.projects.get() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/projects", method="GET", request_options=request_options - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Projects, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create( - self, - *, - name: str, - retention: int, - metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Project: - """ - Create a new project (requires organization-scoped API key) - - Parameters - ---------- - name : str - - retention : int - Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. - - metadata : typing.Optional[typing.Dict[str, typing.Any]] - Optional metadata for the project - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Project - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.projects.create( - name="name", - retention=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/projects", - method="POST", - json={"name": name, "metadata": metadata, "retention": retention}, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def update( - self, - project_id: str, - *, - name: str, - retention: int, - metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Project: - """ - Update a project by ID (requires organization-scoped API key). - - Parameters - ---------- - project_id : str - - name : str - - retention : int - Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. - - metadata : typing.Optional[typing.Dict[str, typing.Any]] - Optional metadata for the project - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Project - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.projects.update( - project_id="projectId", - name="name", - retention=1, - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}", - method="PUT", - json={"name": name, "metadata": metadata, "retention": retention}, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete( - self, - project_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> ProjectDeletionResponse: - """ - Delete a project by ID (requires organization-scoped API key). Project deletion is processed asynchronously. - - Parameters - ---------- - project_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ProjectDeletionResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.projects.delete( - project_id="projectId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - ProjectDeletionResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_api_keys( - self, - project_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> ApiKeyList: - """ - Get all API keys for a project (requires organization-scoped API key) - - Parameters - ---------- - project_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ApiKeyList - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.projects.get_api_keys( - project_id="projectId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ApiKeyList, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create_api_key( - self, - project_id: str, - *, - note: typing.Optional[str] = OMIT, - public_key: typing.Optional[str] = OMIT, - secret_key: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> ApiKeyResponse: - """ - Create a new API key for a project (requires organization-scoped API key) - - Parameters - ---------- - project_id : str - - note : typing.Optional[str] - Optional note for the API key - - public_key : typing.Optional[str] - Optional predefined public key. Must start with 'pk-lf-'. If provided, secretKey must also be provided. - - secret_key : typing.Optional[str] - Optional predefined secret key. Must start with 'sk-lf-'. If provided, publicKey must also be provided. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ApiKeyResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.projects.create_api_key( - project_id="projectId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys", - method="POST", - json={"note": note, "publicKey": public_key, "secretKey": secret_key}, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ApiKeyResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete_api_key( - self, - project_id: str, - api_key_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> ApiKeyDeletionResponse: - """ - Delete an API key for a project (requires organization-scoped API key) - - Parameters - ---------- - project_id : str - - api_key_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ApiKeyDeletionResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.projects.delete_api_key( - project_id="projectId", - api_key_id="apiKeyId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys/{jsonable_encoder(api_key_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - ApiKeyDeletionResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncProjectsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def get( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> Projects: - """ - Get Project associated with API key (requires project-scoped API key). You can use GET /api/public/organizations/projects to get all projects with an organization-scoped key. - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Projects - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.projects.get() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/projects", method="GET", request_options=request_options - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Projects, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create( - self, - *, - name: str, - retention: int, - metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Project: - """ - Create a new project (requires organization-scoped API key) - - Parameters - ---------- - name : str - - retention : int - Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. - - metadata : typing.Optional[typing.Dict[str, typing.Any]] - Optional metadata for the project - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Project - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.projects.create( - name="name", - retention=1, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/projects", - method="POST", - json={"name": name, "metadata": metadata, "retention": retention}, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def update( - self, - project_id: str, - *, - name: str, - retention: int, - metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> Project: - """ - Update a project by ID (requires organization-scoped API key). - - Parameters - ---------- - project_id : str - - name : str - - retention : int - Number of days to retain data. Must be 0 or at least 3 days. Requires data-retention entitlement for non-zero values. Optional. - - metadata : typing.Optional[typing.Dict[str, typing.Any]] - Optional metadata for the project - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Project - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.projects.update( - project_id="projectId", - name="name", - retention=1, - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}", - method="PUT", - json={"name": name, "metadata": metadata, "retention": retention}, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Project, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete( - self, - project_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> ProjectDeletionResponse: - """ - Delete a project by ID (requires organization-scoped API key). Project deletion is processed asynchronously. - - Parameters - ---------- - project_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ProjectDeletionResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.projects.delete( - project_id="projectId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - ProjectDeletionResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_api_keys( - self, - project_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> ApiKeyList: - """ - Get all API keys for a project (requires organization-scoped API key) - - Parameters - ---------- - project_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ApiKeyList - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.projects.get_api_keys( - project_id="projectId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ApiKeyList, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create_api_key( - self, - project_id: str, - *, - note: typing.Optional[str] = OMIT, - public_key: typing.Optional[str] = OMIT, - secret_key: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> ApiKeyResponse: - """ - Create a new API key for a project (requires organization-scoped API key) - - Parameters - ---------- - project_id : str - - note : typing.Optional[str] - Optional note for the API key - - public_key : typing.Optional[str] - Optional predefined public key. Must start with 'pk-lf-'. If provided, secretKey must also be provided. - - secret_key : typing.Optional[str] - Optional predefined secret key. Must start with 'sk-lf-'. If provided, publicKey must also be provided. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ApiKeyResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.projects.create_api_key( - project_id="projectId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys", - method="POST", - json={"note": note, "publicKey": public_key, "secretKey": secret_key}, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ApiKeyResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete_api_key( - self, - project_id: str, - api_key_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> ApiKeyDeletionResponse: - """ - Delete an API key for a project (requires organization-scoped API key) - - Parameters - ---------- - project_id : str - - api_key_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ApiKeyDeletionResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.projects.delete_api_key( - project_id="projectId", - api_key_id="apiKeyId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/projects/{jsonable_encoder(project_id)}/apiKeys/{jsonable_encoder(api_key_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - ApiKeyDeletionResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/projects/types/__init__.py b/langfuse/api/resources/projects/types/__init__.py deleted file mode 100644 index c59b62a62..000000000 --- a/langfuse/api/resources/projects/types/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .api_key_deletion_response import ApiKeyDeletionResponse -from .api_key_list import ApiKeyList -from .api_key_response import ApiKeyResponse -from .api_key_summary import ApiKeySummary -from .project import Project -from .project_deletion_response import ProjectDeletionResponse -from .projects import Projects - -__all__ = [ - "ApiKeyDeletionResponse", - "ApiKeyList", - "ApiKeyResponse", - "ApiKeySummary", - "Project", - "ProjectDeletionResponse", - "Projects", -] diff --git a/langfuse/api/resources/projects/types/api_key_deletion_response.py b/langfuse/api/resources/projects/types/api_key_deletion_response.py deleted file mode 100644 index 6084400de..000000000 --- a/langfuse/api/resources/projects/types/api_key_deletion_response.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ApiKeyDeletionResponse(pydantic_v1.BaseModel): - """ - Response for API key deletion - """ - - success: bool - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/projects/types/api_key_list.py b/langfuse/api/resources/projects/types/api_key_list.py deleted file mode 100644 index 0a798ddbf..000000000 --- a/langfuse/api/resources/projects/types/api_key_list.py +++ /dev/null @@ -1,49 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .api_key_summary import ApiKeySummary - - -class ApiKeyList(pydantic_v1.BaseModel): - """ - List of API keys for a project - """ - - api_keys: typing.List[ApiKeySummary] = pydantic_v1.Field(alias="apiKeys") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/projects/types/api_key_response.py b/langfuse/api/resources/projects/types/api_key_response.py deleted file mode 100644 index fc9364faf..000000000 --- a/langfuse/api/resources/projects/types/api_key_response.py +++ /dev/null @@ -1,53 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ApiKeyResponse(pydantic_v1.BaseModel): - """ - Response for API key creation - """ - - id: str - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - public_key: str = pydantic_v1.Field(alias="publicKey") - secret_key: str = pydantic_v1.Field(alias="secretKey") - display_secret_key: str = pydantic_v1.Field(alias="displaySecretKey") - note: typing.Optional[str] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/projects/types/api_key_summary.py b/langfuse/api/resources/projects/types/api_key_summary.py deleted file mode 100644 index b95633731..000000000 --- a/langfuse/api/resources/projects/types/api_key_summary.py +++ /dev/null @@ -1,58 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ApiKeySummary(pydantic_v1.BaseModel): - """ - Summary of an API key - """ - - id: str - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - expires_at: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="expiresAt", default=None - ) - last_used_at: typing.Optional[dt.datetime] = pydantic_v1.Field( - alias="lastUsedAt", default=None - ) - note: typing.Optional[str] = None - public_key: str = pydantic_v1.Field(alias="publicKey") - display_secret_key: str = pydantic_v1.Field(alias="displaySecretKey") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/projects/types/project.py b/langfuse/api/resources/projects/types/project.py deleted file mode 100644 index cf257d406..000000000 --- a/langfuse/api/resources/projects/types/project.py +++ /dev/null @@ -1,56 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class Project(pydantic_v1.BaseModel): - id: str - name: str - metadata: typing.Dict[str, typing.Any] = pydantic_v1.Field() - """ - Metadata for the project - """ - - retention_days: typing.Optional[int] = pydantic_v1.Field( - alias="retentionDays", default=None - ) - """ - Number of days to retain data. Null or 0 means no retention. Omitted if no retention is configured. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/projects/types/project_deletion_response.py b/langfuse/api/resources/projects/types/project_deletion_response.py deleted file mode 100644 index 62c05d3d8..000000000 --- a/langfuse/api/resources/projects/types/project_deletion_response.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ProjectDeletionResponse(pydantic_v1.BaseModel): - success: bool - message: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/projects/types/projects.py b/langfuse/api/resources/projects/types/projects.py deleted file mode 100644 index c5eaabfbd..000000000 --- a/langfuse/api/resources/projects/types/projects.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .project import Project - - -class Projects(pydantic_v1.BaseModel): - data: typing.List[Project] - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompt_version/client.py b/langfuse/api/resources/prompt_version/client.py deleted file mode 100644 index 5387c6e25..000000000 --- a/langfuse/api/resources/prompt_version/client.py +++ /dev/null @@ -1,199 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from ..prompts.types.prompt import Prompt - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class PromptVersionClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def update( - self, - name: str, - version: int, - *, - new_labels: typing.Sequence[str], - request_options: typing.Optional[RequestOptions] = None, - ) -> Prompt: - """ - Update labels for a specific prompt version - - Parameters - ---------- - name : str - The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), - the folder path must be URL encoded. - - version : int - Version of the prompt to update - - new_labels : typing.Sequence[str] - New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Prompt - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.prompt_version.update( - name="name", - version=1, - new_labels=["newLabels", "newLabels"], - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/v2/prompts/{jsonable_encoder(name)}/versions/{jsonable_encoder(version)}", - method="PATCH", - json={"newLabels": new_labels}, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Prompt, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncPromptVersionClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def update( - self, - name: str, - version: int, - *, - new_labels: typing.Sequence[str], - request_options: typing.Optional[RequestOptions] = None, - ) -> Prompt: - """ - Update labels for a specific prompt version - - Parameters - ---------- - name : str - The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), - the folder path must be URL encoded. - - version : int - Version of the prompt to update - - new_labels : typing.Sequence[str] - New labels for the prompt version. Labels are unique across versions. The "latest" label is reserved and managed by Langfuse. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Prompt - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.prompt_version.update( - name="name", - version=1, - new_labels=["newLabels", "newLabels"], - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/v2/prompts/{jsonable_encoder(name)}/versions/{jsonable_encoder(version)}", - method="PATCH", - json={"newLabels": new_labels}, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Prompt, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/prompts/__init__.py b/langfuse/api/resources/prompts/__init__.py deleted file mode 100644 index ea2f2f56a..000000000 --- a/langfuse/api/resources/prompts/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - BasePrompt, - ChatMessage, - ChatMessageWithPlaceholders, - ChatMessageWithPlaceholders_Chatmessage, - ChatMessageWithPlaceholders_Placeholder, - ChatPrompt, - CreateChatPromptRequest, - CreatePromptRequest, - CreatePromptRequest_Chat, - CreatePromptRequest_Text, - CreateTextPromptRequest, - PlaceholderMessage, - Prompt, - PromptMeta, - PromptMetaListResponse, - PromptType, - Prompt_Chat, - Prompt_Text, - TextPrompt, -) - -__all__ = [ - "BasePrompt", - "ChatMessage", - "ChatMessageWithPlaceholders", - "ChatMessageWithPlaceholders_Chatmessage", - "ChatMessageWithPlaceholders_Placeholder", - "ChatPrompt", - "CreateChatPromptRequest", - "CreatePromptRequest", - "CreatePromptRequest_Chat", - "CreatePromptRequest_Text", - "CreateTextPromptRequest", - "PlaceholderMessage", - "Prompt", - "PromptMeta", - "PromptMetaListResponse", - "PromptType", - "Prompt_Chat", - "Prompt_Text", - "TextPrompt", -] diff --git a/langfuse/api/resources/prompts/client.py b/langfuse/api/resources/prompts/client.py deleted file mode 100644 index b8d6f31d4..000000000 --- a/langfuse/api/resources/prompts/client.py +++ /dev/null @@ -1,749 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.datetime_utils import serialize_datetime -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from .types.create_prompt_request import CreatePromptRequest -from .types.prompt import Prompt -from .types.prompt_meta_list_response import PromptMetaListResponse - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class PromptsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def get( - self, - prompt_name: str, - *, - version: typing.Optional[int] = None, - label: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> Prompt: - """ - Get a prompt - - Parameters - ---------- - prompt_name : str - The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), - the folder path must be URL encoded. - - version : typing.Optional[int] - Version of the prompt to be retrieved. - - label : typing.Optional[str] - Label of the prompt to be retrieved. Defaults to "production" if no label or version is set. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Prompt - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.prompts.get( - prompt_name="promptName", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/v2/prompts/{jsonable_encoder(prompt_name)}", - method="GET", - params={"version": version, "label": label}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Prompt, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list( - self, - *, - name: typing.Optional[str] = None, - label: typing.Optional[str] = None, - tag: typing.Optional[str] = None, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - from_updated_at: typing.Optional[dt.datetime] = None, - to_updated_at: typing.Optional[dt.datetime] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PromptMetaListResponse: - """ - Get a list of prompt names with versions and labels - - Parameters - ---------- - name : typing.Optional[str] - - label : typing.Optional[str] - - tag : typing.Optional[str] - - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - from_updated_at : typing.Optional[dt.datetime] - Optional filter to only include prompt versions created/updated on or after a certain datetime (ISO 8601) - - to_updated_at : typing.Optional[dt.datetime] - Optional filter to only include prompt versions created/updated before a certain datetime (ISO 8601) - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PromptMetaListResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.prompts.list() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/v2/prompts", - method="GET", - params={ - "name": name, - "label": label, - "tag": tag, - "page": page, - "limit": limit, - "fromUpdatedAt": serialize_datetime(from_updated_at) - if from_updated_at is not None - else None, - "toUpdatedAt": serialize_datetime(to_updated_at) - if to_updated_at is not None - else None, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - PromptMetaListResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create( - self, - *, - request: CreatePromptRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> Prompt: - """ - Create a new version for the prompt with the given `name` - - Parameters - ---------- - request : CreatePromptRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Prompt - - Examples - -------- - from langfuse import ( - ChatMessageWithPlaceholders_Chatmessage, - CreatePromptRequest_Chat, - ) - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.prompts.create( - request=CreatePromptRequest_Chat( - name="name", - prompt=[ - ChatMessageWithPlaceholders_Chatmessage( - role="role", - content="content", - ), - ChatMessageWithPlaceholders_Chatmessage( - role="role", - content="content", - ), - ], - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/v2/prompts", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Prompt, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete( - self, - prompt_name: str, - *, - label: typing.Optional[str] = None, - version: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> None: - """ - Delete prompt versions. If neither version nor label is specified, all versions of the prompt are deleted. - - Parameters - ---------- - prompt_name : str - The name of the prompt - - label : typing.Optional[str] - Optional label to filter deletion. If specified, deletes all prompt versions that have this label. - - version : typing.Optional[int] - Optional version to filter deletion. If specified, deletes only this specific version of the prompt. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.prompts.delete( - prompt_name="promptName", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/v2/prompts/{jsonable_encoder(prompt_name)}", - method="DELETE", - params={"label": label, "version": version}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncPromptsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def get( - self, - prompt_name: str, - *, - version: typing.Optional[int] = None, - label: typing.Optional[str] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> Prompt: - """ - Get a prompt - - Parameters - ---------- - prompt_name : str - The name of the prompt. If the prompt is in a folder (e.g., "folder/subfolder/prompt-name"), - the folder path must be URL encoded. - - version : typing.Optional[int] - Version of the prompt to be retrieved. - - label : typing.Optional[str] - Label of the prompt to be retrieved. Defaults to "production" if no label or version is set. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Prompt - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.prompts.get( - prompt_name="promptName", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/v2/prompts/{jsonable_encoder(prompt_name)}", - method="GET", - params={"version": version, "label": label}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Prompt, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list( - self, - *, - name: typing.Optional[str] = None, - label: typing.Optional[str] = None, - tag: typing.Optional[str] = None, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - from_updated_at: typing.Optional[dt.datetime] = None, - to_updated_at: typing.Optional[dt.datetime] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PromptMetaListResponse: - """ - Get a list of prompt names with versions and labels - - Parameters - ---------- - name : typing.Optional[str] - - label : typing.Optional[str] - - tag : typing.Optional[str] - - page : typing.Optional[int] - page number, starts at 1 - - limit : typing.Optional[int] - limit of items per page - - from_updated_at : typing.Optional[dt.datetime] - Optional filter to only include prompt versions created/updated on or after a certain datetime (ISO 8601) - - to_updated_at : typing.Optional[dt.datetime] - Optional filter to only include prompt versions created/updated before a certain datetime (ISO 8601) - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PromptMetaListResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.prompts.list() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/v2/prompts", - method="GET", - params={ - "name": name, - "label": label, - "tag": tag, - "page": page, - "limit": limit, - "fromUpdatedAt": serialize_datetime(from_updated_at) - if from_updated_at is not None - else None, - "toUpdatedAt": serialize_datetime(to_updated_at) - if to_updated_at is not None - else None, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as( - PromptMetaListResponse, _response.json() - ) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create( - self, - *, - request: CreatePromptRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> Prompt: - """ - Create a new version for the prompt with the given `name` - - Parameters - ---------- - request : CreatePromptRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - Prompt - - Examples - -------- - import asyncio - - from langfuse import ( - ChatMessageWithPlaceholders_Chatmessage, - CreatePromptRequest_Chat, - ) - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.prompts.create( - request=CreatePromptRequest_Chat( - name="name", - prompt=[ - ChatMessageWithPlaceholders_Chatmessage( - role="role", - content="content", - ), - ChatMessageWithPlaceholders_Chatmessage( - role="role", - content="content", - ), - ], - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/v2/prompts", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Prompt, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete( - self, - prompt_name: str, - *, - label: typing.Optional[str] = None, - version: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> None: - """ - Delete prompt versions. If neither version nor label is specified, all versions of the prompt are deleted. - - Parameters - ---------- - prompt_name : str - The name of the prompt - - label : typing.Optional[str] - Optional label to filter deletion. If specified, deletes all prompt versions that have this label. - - version : typing.Optional[int] - Optional version to filter deletion. If specified, deletes only this specific version of the prompt. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.prompts.delete( - prompt_name="promptName", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/v2/prompts/{jsonable_encoder(prompt_name)}", - method="DELETE", - params={"label": label, "version": version}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/prompts/types/__init__.py b/langfuse/api/resources/prompts/types/__init__.py deleted file mode 100644 index 6678ec262..000000000 --- a/langfuse/api/resources/prompts/types/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .base_prompt import BasePrompt -from .chat_message import ChatMessage -from .chat_message_with_placeholders import ( - ChatMessageWithPlaceholders, - ChatMessageWithPlaceholders_Chatmessage, - ChatMessageWithPlaceholders_Placeholder, -) -from .chat_prompt import ChatPrompt -from .create_chat_prompt_request import CreateChatPromptRequest -from .create_prompt_request import ( - CreatePromptRequest, - CreatePromptRequest_Chat, - CreatePromptRequest_Text, -) -from .create_text_prompt_request import CreateTextPromptRequest -from .placeholder_message import PlaceholderMessage -from .prompt import Prompt, Prompt_Chat, Prompt_Text -from .prompt_meta import PromptMeta -from .prompt_meta_list_response import PromptMetaListResponse -from .prompt_type import PromptType -from .text_prompt import TextPrompt - -__all__ = [ - "BasePrompt", - "ChatMessage", - "ChatMessageWithPlaceholders", - "ChatMessageWithPlaceholders_Chatmessage", - "ChatMessageWithPlaceholders_Placeholder", - "ChatPrompt", - "CreateChatPromptRequest", - "CreatePromptRequest", - "CreatePromptRequest_Chat", - "CreatePromptRequest_Text", - "CreateTextPromptRequest", - "PlaceholderMessage", - "Prompt", - "PromptMeta", - "PromptMetaListResponse", - "PromptType", - "Prompt_Chat", - "Prompt_Text", - "TextPrompt", -] diff --git a/langfuse/api/resources/prompts/types/base_prompt.py b/langfuse/api/resources/prompts/types/base_prompt.py deleted file mode 100644 index eff295cc5..000000000 --- a/langfuse/api/resources/prompts/types/base_prompt.py +++ /dev/null @@ -1,69 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class BasePrompt(pydantic_v1.BaseModel): - name: str - version: int - config: typing.Any - labels: typing.List[str] = pydantic_v1.Field() - """ - List of deployment labels of this prompt version. - """ - - tags: typing.List[str] = pydantic_v1.Field() - """ - List of tags. Used to filter via UI and API. The same across versions of a prompt. - """ - - commit_message: typing.Optional[str] = pydantic_v1.Field( - alias="commitMessage", default=None - ) - """ - Commit message for this prompt version. - """ - - resolution_graph: typing.Optional[typing.Dict[str, typing.Any]] = pydantic_v1.Field( - alias="resolutionGraph", default=None - ) - """ - The dependency resolution graph for the current prompt. Null if prompt has no dependencies. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/chat_message.py b/langfuse/api/resources/prompts/types/chat_message.py deleted file mode 100644 index d009bc8cf..000000000 --- a/langfuse/api/resources/prompts/types/chat_message.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ChatMessage(pydantic_v1.BaseModel): - role: str - content: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/chat_message_with_placeholders.py b/langfuse/api/resources/prompts/types/chat_message_with_placeholders.py deleted file mode 100644 index dc12d5073..000000000 --- a/langfuse/api/resources/prompts/types/chat_message_with_placeholders.py +++ /dev/null @@ -1,87 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from __future__ import annotations - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ChatMessageWithPlaceholders_Chatmessage(pydantic_v1.BaseModel): - role: str - content: str - type: typing.Literal["chatmessage"] = "chatmessage" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class ChatMessageWithPlaceholders_Placeholder(pydantic_v1.BaseModel): - name: str - type: typing.Literal["placeholder"] = "placeholder" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -ChatMessageWithPlaceholders = typing.Union[ - ChatMessageWithPlaceholders_Chatmessage, ChatMessageWithPlaceholders_Placeholder -] diff --git a/langfuse/api/resources/prompts/types/chat_prompt.py b/langfuse/api/resources/prompts/types/chat_prompt.py deleted file mode 100644 index 494449ea2..000000000 --- a/langfuse/api/resources/prompts/types/chat_prompt.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_prompt import BasePrompt -from .chat_message_with_placeholders import ChatMessageWithPlaceholders - - -class ChatPrompt(BasePrompt): - prompt: typing.List[ChatMessageWithPlaceholders] - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/create_chat_prompt_request.py b/langfuse/api/resources/prompts/types/create_chat_prompt_request.py deleted file mode 100644 index 1442164a6..000000000 --- a/langfuse/api/resources/prompts/types/create_chat_prompt_request.py +++ /dev/null @@ -1,63 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .chat_message_with_placeholders import ChatMessageWithPlaceholders - - -class CreateChatPromptRequest(pydantic_v1.BaseModel): - name: str - prompt: typing.List[ChatMessageWithPlaceholders] - config: typing.Optional[typing.Any] = None - labels: typing.Optional[typing.List[str]] = pydantic_v1.Field(default=None) - """ - List of deployment labels of this prompt version. - """ - - tags: typing.Optional[typing.List[str]] = pydantic_v1.Field(default=None) - """ - List of tags to apply to all versions of this prompt. - """ - - commit_message: typing.Optional[str] = pydantic_v1.Field( - alias="commitMessage", default=None - ) - """ - Commit message for this prompt version. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/create_prompt_request.py b/langfuse/api/resources/prompts/types/create_prompt_request.py deleted file mode 100644 index b9518a7c4..000000000 --- a/langfuse/api/resources/prompts/types/create_prompt_request.py +++ /dev/null @@ -1,103 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from __future__ import annotations - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .chat_message_with_placeholders import ChatMessageWithPlaceholders - - -class CreatePromptRequest_Chat(pydantic_v1.BaseModel): - name: str - prompt: typing.List[ChatMessageWithPlaceholders] - config: typing.Optional[typing.Any] = None - labels: typing.Optional[typing.List[str]] = None - tags: typing.Optional[typing.List[str]] = None - commit_message: typing.Optional[str] = pydantic_v1.Field( - alias="commitMessage", default=None - ) - type: typing.Literal["chat"] = "chat" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class CreatePromptRequest_Text(pydantic_v1.BaseModel): - name: str - prompt: str - config: typing.Optional[typing.Any] = None - labels: typing.Optional[typing.List[str]] = None - tags: typing.Optional[typing.List[str]] = None - commit_message: typing.Optional[str] = pydantic_v1.Field( - alias="commitMessage", default=None - ) - type: typing.Literal["text"] = "text" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -CreatePromptRequest = typing.Union[CreatePromptRequest_Chat, CreatePromptRequest_Text] diff --git a/langfuse/api/resources/prompts/types/create_text_prompt_request.py b/langfuse/api/resources/prompts/types/create_text_prompt_request.py deleted file mode 100644 index d35fbb24d..000000000 --- a/langfuse/api/resources/prompts/types/create_text_prompt_request.py +++ /dev/null @@ -1,62 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class CreateTextPromptRequest(pydantic_v1.BaseModel): - name: str - prompt: str - config: typing.Optional[typing.Any] = None - labels: typing.Optional[typing.List[str]] = pydantic_v1.Field(default=None) - """ - List of deployment labels of this prompt version. - """ - - tags: typing.Optional[typing.List[str]] = pydantic_v1.Field(default=None) - """ - List of tags to apply to all versions of this prompt. - """ - - commit_message: typing.Optional[str] = pydantic_v1.Field( - alias="commitMessage", default=None - ) - """ - Commit message for this prompt version. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/placeholder_message.py b/langfuse/api/resources/prompts/types/placeholder_message.py deleted file mode 100644 index a3352b391..000000000 --- a/langfuse/api/resources/prompts/types/placeholder_message.py +++ /dev/null @@ -1,42 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class PlaceholderMessage(pydantic_v1.BaseModel): - name: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/prompt.py b/langfuse/api/resources/prompts/types/prompt.py deleted file mode 100644 index 1ad894879..000000000 --- a/langfuse/api/resources/prompts/types/prompt.py +++ /dev/null @@ -1,111 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from __future__ import annotations - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .chat_message_with_placeholders import ChatMessageWithPlaceholders - - -class Prompt_Chat(pydantic_v1.BaseModel): - prompt: typing.List[ChatMessageWithPlaceholders] - name: str - version: int - config: typing.Any - labels: typing.List[str] - tags: typing.List[str] - commit_message: typing.Optional[str] = pydantic_v1.Field( - alias="commitMessage", default=None - ) - resolution_graph: typing.Optional[typing.Dict[str, typing.Any]] = pydantic_v1.Field( - alias="resolutionGraph", default=None - ) - type: typing.Literal["chat"] = "chat" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class Prompt_Text(pydantic_v1.BaseModel): - prompt: str - name: str - version: int - config: typing.Any - labels: typing.List[str] - tags: typing.List[str] - commit_message: typing.Optional[str] = pydantic_v1.Field( - alias="commitMessage", default=None - ) - resolution_graph: typing.Optional[typing.Dict[str, typing.Any]] = pydantic_v1.Field( - alias="resolutionGraph", default=None - ) - type: typing.Literal["text"] = "text" - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -Prompt = typing.Union[Prompt_Chat, Prompt_Text] diff --git a/langfuse/api/resources/prompts/types/prompt_meta.py b/langfuse/api/resources/prompts/types/prompt_meta.py deleted file mode 100644 index 35f8a06cf..000000000 --- a/langfuse/api/resources/prompts/types/prompt_meta.py +++ /dev/null @@ -1,58 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .prompt_type import PromptType - - -class PromptMeta(pydantic_v1.BaseModel): - name: str - type: PromptType = pydantic_v1.Field() - """ - Indicates whether the prompt is a text or chat prompt. - """ - - versions: typing.List[int] - labels: typing.List[str] - tags: typing.List[str] - last_updated_at: dt.datetime = pydantic_v1.Field(alias="lastUpdatedAt") - last_config: typing.Any = pydantic_v1.Field(alias="lastConfig") - """ - Config object of the most recent prompt version that matches the filters (if any are provided) - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/prompt_meta_list_response.py b/langfuse/api/resources/prompts/types/prompt_meta_list_response.py deleted file mode 100644 index d3dccf650..000000000 --- a/langfuse/api/resources/prompts/types/prompt_meta_list_response.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...utils.resources.pagination.types.meta_response import MetaResponse -from .prompt_meta import PromptMeta - - -class PromptMetaListResponse(pydantic_v1.BaseModel): - data: typing.List[PromptMeta] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/prompts/types/prompt_type.py b/langfuse/api/resources/prompts/types/prompt_type.py deleted file mode 100644 index 958d544a6..000000000 --- a/langfuse/api/resources/prompts/types/prompt_type.py +++ /dev/null @@ -1,19 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import enum -import typing - -T_Result = typing.TypeVar("T_Result") - - -class PromptType(str, enum.Enum): - CHAT = "chat" - TEXT = "text" - - def visit( - self, chat: typing.Callable[[], T_Result], text: typing.Callable[[], T_Result] - ) -> T_Result: - if self is PromptType.CHAT: - return chat() - if self is PromptType.TEXT: - return text() diff --git a/langfuse/api/resources/prompts/types/text_prompt.py b/langfuse/api/resources/prompts/types/text_prompt.py deleted file mode 100644 index e149ea322..000000000 --- a/langfuse/api/resources/prompts/types/text_prompt.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .base_prompt import BasePrompt - - -class TextPrompt(BasePrompt): - prompt: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/__init__.py b/langfuse/api/resources/scim/__init__.py deleted file mode 100644 index 29655a8da..000000000 --- a/langfuse/api/resources/scim/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - AuthenticationScheme, - BulkConfig, - EmptyResponse, - FilterConfig, - ResourceMeta, - ResourceType, - ResourceTypesResponse, - SchemaExtension, - SchemaResource, - SchemasResponse, - ScimEmail, - ScimFeatureSupport, - ScimName, - ScimUser, - ScimUsersListResponse, - ServiceProviderConfig, - UserMeta, -) - -__all__ = [ - "AuthenticationScheme", - "BulkConfig", - "EmptyResponse", - "FilterConfig", - "ResourceMeta", - "ResourceType", - "ResourceTypesResponse", - "SchemaExtension", - "SchemaResource", - "SchemasResponse", - "ScimEmail", - "ScimFeatureSupport", - "ScimName", - "ScimUser", - "ScimUsersListResponse", - "ServiceProviderConfig", - "UserMeta", -] diff --git a/langfuse/api/resources/scim/client.py b/langfuse/api/resources/scim/client.py deleted file mode 100644 index 38523a4f9..000000000 --- a/langfuse/api/resources/scim/client.py +++ /dev/null @@ -1,1042 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from .types.empty_response import EmptyResponse -from .types.resource_types_response import ResourceTypesResponse -from .types.schemas_response import SchemasResponse -from .types.scim_email import ScimEmail -from .types.scim_name import ScimName -from .types.scim_user import ScimUser -from .types.scim_users_list_response import ScimUsersListResponse -from .types.service_provider_config import ServiceProviderConfig - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class ScimClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def get_service_provider_config( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> ServiceProviderConfig: - """ - Get SCIM Service Provider Configuration (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ServiceProviderConfig - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.scim.get_service_provider_config() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/scim/ServiceProviderConfig", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ServiceProviderConfig, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_resource_types( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> ResourceTypesResponse: - """ - Get SCIM Resource Types (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ResourceTypesResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.scim.get_resource_types() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/scim/ResourceTypes", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ResourceTypesResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_schemas( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> SchemasResponse: - """ - Get SCIM Schemas (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SchemasResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.scim.get_schemas() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/scim/Schemas", method="GET", request_options=request_options - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(SchemasResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def list_users( - self, - *, - filter: typing.Optional[str] = None, - start_index: typing.Optional[int] = None, - count: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> ScimUsersListResponse: - """ - List users in the organization (requires organization-scoped API key) - - Parameters - ---------- - filter : typing.Optional[str] - Filter expression (e.g. userName eq "value") - - start_index : typing.Optional[int] - 1-based index of the first result to return (default 1) - - count : typing.Optional[int] - Maximum number of results to return (default 100) - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScimUsersListResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.scim.list_users() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/scim/Users", - method="GET", - params={"filter": filter, "startIndex": start_index, "count": count}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScimUsersListResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def create_user( - self, - *, - user_name: str, - name: ScimName, - emails: typing.Optional[typing.Sequence[ScimEmail]] = OMIT, - active: typing.Optional[bool] = OMIT, - password: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> ScimUser: - """ - Create a new user in the organization (requires organization-scoped API key) - - Parameters - ---------- - user_name : str - User's email address (required) - - name : ScimName - User's name information - - emails : typing.Optional[typing.Sequence[ScimEmail]] - User's email addresses - - active : typing.Optional[bool] - Whether the user is active - - password : typing.Optional[str] - Initial password for the user - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScimUser - - Examples - -------- - from langfuse import ScimName - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.scim.create_user( - user_name="userName", - name=ScimName(), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/scim/Users", - method="POST", - json={ - "userName": user_name, - "name": name, - "emails": emails, - "active": active, - "password": password, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScimUser, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_user( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ScimUser: - """ - Get a specific user by ID (requires organization-scoped API key) - - Parameters - ---------- - user_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScimUser - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.scim.get_user( - user_id="userId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/scim/Users/{jsonable_encoder(user_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScimUser, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete_user( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> EmptyResponse: - """ - Remove a user from the organization (requires organization-scoped API key). Note that this only removes the user from the organization but does not delete the user entity itself. - - Parameters - ---------- - user_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - EmptyResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.scim.delete_user( - user_id="userId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/scim/Users/{jsonable_encoder(user_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(EmptyResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncScimClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def get_service_provider_config( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> ServiceProviderConfig: - """ - Get SCIM Service Provider Configuration (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ServiceProviderConfig - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.scim.get_service_provider_config() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/scim/ServiceProviderConfig", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ServiceProviderConfig, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_resource_types( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> ResourceTypesResponse: - """ - Get SCIM Resource Types (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ResourceTypesResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.scim.get_resource_types() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/scim/ResourceTypes", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ResourceTypesResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_schemas( - self, *, request_options: typing.Optional[RequestOptions] = None - ) -> SchemasResponse: - """ - Get SCIM Schemas (requires organization-scoped API key) - - Parameters - ---------- - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SchemasResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.scim.get_schemas() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/scim/Schemas", method="GET", request_options=request_options - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(SchemasResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def list_users( - self, - *, - filter: typing.Optional[str] = None, - start_index: typing.Optional[int] = None, - count: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> ScimUsersListResponse: - """ - List users in the organization (requires organization-scoped API key) - - Parameters - ---------- - filter : typing.Optional[str] - Filter expression (e.g. userName eq "value") - - start_index : typing.Optional[int] - 1-based index of the first result to return (default 1) - - count : typing.Optional[int] - Maximum number of results to return (default 100) - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScimUsersListResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.scim.list_users() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/scim/Users", - method="GET", - params={"filter": filter, "startIndex": start_index, "count": count}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScimUsersListResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def create_user( - self, - *, - user_name: str, - name: ScimName, - emails: typing.Optional[typing.Sequence[ScimEmail]] = OMIT, - active: typing.Optional[bool] = OMIT, - password: typing.Optional[str] = OMIT, - request_options: typing.Optional[RequestOptions] = None, - ) -> ScimUser: - """ - Create a new user in the organization (requires organization-scoped API key) - - Parameters - ---------- - user_name : str - User's email address (required) - - name : ScimName - User's name information - - emails : typing.Optional[typing.Sequence[ScimEmail]] - User's email addresses - - active : typing.Optional[bool] - Whether the user is active - - password : typing.Optional[str] - Initial password for the user - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScimUser - - Examples - -------- - import asyncio - - from langfuse import ScimName - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.scim.create_user( - user_name="userName", - name=ScimName(), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/scim/Users", - method="POST", - json={ - "userName": user_name, - "name": name, - "emails": emails, - "active": active, - "password": password, - }, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScimUser, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_user( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ScimUser: - """ - Get a specific user by ID (requires organization-scoped API key) - - Parameters - ---------- - user_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScimUser - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.scim.get_user( - user_id="userId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/scim/Users/{jsonable_encoder(user_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScimUser, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete_user( - self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> EmptyResponse: - """ - Remove a user from the organization (requires organization-scoped API key). Note that this only removes the user from the organization but does not delete the user entity itself. - - Parameters - ---------- - user_id : str - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - EmptyResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.scim.delete_user( - user_id="userId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/scim/Users/{jsonable_encoder(user_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(EmptyResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/scim/types/__init__.py b/langfuse/api/resources/scim/types/__init__.py deleted file mode 100644 index c0b60e8c2..000000000 --- a/langfuse/api/resources/scim/types/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .authentication_scheme import AuthenticationScheme -from .bulk_config import BulkConfig -from .empty_response import EmptyResponse -from .filter_config import FilterConfig -from .resource_meta import ResourceMeta -from .resource_type import ResourceType -from .resource_types_response import ResourceTypesResponse -from .schema_extension import SchemaExtension -from .schema_resource import SchemaResource -from .schemas_response import SchemasResponse -from .scim_email import ScimEmail -from .scim_feature_support import ScimFeatureSupport -from .scim_name import ScimName -from .scim_user import ScimUser -from .scim_users_list_response import ScimUsersListResponse -from .service_provider_config import ServiceProviderConfig -from .user_meta import UserMeta - -__all__ = [ - "AuthenticationScheme", - "BulkConfig", - "EmptyResponse", - "FilterConfig", - "ResourceMeta", - "ResourceType", - "ResourceTypesResponse", - "SchemaExtension", - "SchemaResource", - "SchemasResponse", - "ScimEmail", - "ScimFeatureSupport", - "ScimName", - "ScimUser", - "ScimUsersListResponse", - "ServiceProviderConfig", - "UserMeta", -] diff --git a/langfuse/api/resources/scim/types/authentication_scheme.py b/langfuse/api/resources/scim/types/authentication_scheme.py deleted file mode 100644 index 6d6526901..000000000 --- a/langfuse/api/resources/scim/types/authentication_scheme.py +++ /dev/null @@ -1,48 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class AuthenticationScheme(pydantic_v1.BaseModel): - name: str - description: str - spec_uri: str = pydantic_v1.Field(alias="specUri") - type: str - primary: bool - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/bulk_config.py b/langfuse/api/resources/scim/types/bulk_config.py deleted file mode 100644 index 0b41af5cf..000000000 --- a/langfuse/api/resources/scim/types/bulk_config.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class BulkConfig(pydantic_v1.BaseModel): - supported: bool - max_operations: int = pydantic_v1.Field(alias="maxOperations") - max_payload_size: int = pydantic_v1.Field(alias="maxPayloadSize") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/empty_response.py b/langfuse/api/resources/scim/types/empty_response.py deleted file mode 100644 index 82105e8a3..000000000 --- a/langfuse/api/resources/scim/types/empty_response.py +++ /dev/null @@ -1,44 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class EmptyResponse(pydantic_v1.BaseModel): - """ - Empty response for 204 No Content responses - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/filter_config.py b/langfuse/api/resources/scim/types/filter_config.py deleted file mode 100644 index 2bd035867..000000000 --- a/langfuse/api/resources/scim/types/filter_config.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class FilterConfig(pydantic_v1.BaseModel): - supported: bool - max_results: int = pydantic_v1.Field(alias="maxResults") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/resource_meta.py b/langfuse/api/resources/scim/types/resource_meta.py deleted file mode 100644 index a61d14442..000000000 --- a/langfuse/api/resources/scim/types/resource_meta.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ResourceMeta(pydantic_v1.BaseModel): - resource_type: str = pydantic_v1.Field(alias="resourceType") - location: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/resource_type.py b/langfuse/api/resources/scim/types/resource_type.py deleted file mode 100644 index 264dc87cf..000000000 --- a/langfuse/api/resources/scim/types/resource_type.py +++ /dev/null @@ -1,55 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .resource_meta import ResourceMeta -from .schema_extension import SchemaExtension - - -class ResourceType(pydantic_v1.BaseModel): - schemas: typing.Optional[typing.List[str]] = None - id: str - name: str - endpoint: str - description: str - schema_: str = pydantic_v1.Field(alias="schema") - schema_extensions: typing.List[SchemaExtension] = pydantic_v1.Field( - alias="schemaExtensions" - ) - meta: ResourceMeta - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/resource_types_response.py b/langfuse/api/resources/scim/types/resource_types_response.py deleted file mode 100644 index cce65b8d1..000000000 --- a/langfuse/api/resources/scim/types/resource_types_response.py +++ /dev/null @@ -1,47 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .resource_type import ResourceType - - -class ResourceTypesResponse(pydantic_v1.BaseModel): - schemas: typing.List[str] - total_results: int = pydantic_v1.Field(alias="totalResults") - resources: typing.List[ResourceType] = pydantic_v1.Field(alias="Resources") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/schema_extension.py b/langfuse/api/resources/scim/types/schema_extension.py deleted file mode 100644 index c5ede44b9..000000000 --- a/langfuse/api/resources/scim/types/schema_extension.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class SchemaExtension(pydantic_v1.BaseModel): - schema_: str = pydantic_v1.Field(alias="schema") - required: bool - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/schema_resource.py b/langfuse/api/resources/scim/types/schema_resource.py deleted file mode 100644 index e85cda9a0..000000000 --- a/langfuse/api/resources/scim/types/schema_resource.py +++ /dev/null @@ -1,47 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .resource_meta import ResourceMeta - - -class SchemaResource(pydantic_v1.BaseModel): - id: str - name: str - description: str - attributes: typing.List[typing.Any] - meta: ResourceMeta - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/schemas_response.py b/langfuse/api/resources/scim/types/schemas_response.py deleted file mode 100644 index 4c7b8199a..000000000 --- a/langfuse/api/resources/scim/types/schemas_response.py +++ /dev/null @@ -1,47 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .schema_resource import SchemaResource - - -class SchemasResponse(pydantic_v1.BaseModel): - schemas: typing.List[str] - total_results: int = pydantic_v1.Field(alias="totalResults") - resources: typing.List[SchemaResource] = pydantic_v1.Field(alias="Resources") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/scim_email.py b/langfuse/api/resources/scim/types/scim_email.py deleted file mode 100644 index 71b817809..000000000 --- a/langfuse/api/resources/scim/types/scim_email.py +++ /dev/null @@ -1,44 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ScimEmail(pydantic_v1.BaseModel): - primary: bool - value: str - type: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/scim_feature_support.py b/langfuse/api/resources/scim/types/scim_feature_support.py deleted file mode 100644 index 2aedc07b5..000000000 --- a/langfuse/api/resources/scim/types/scim_feature_support.py +++ /dev/null @@ -1,42 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ScimFeatureSupport(pydantic_v1.BaseModel): - supported: bool - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/scim_name.py b/langfuse/api/resources/scim/types/scim_name.py deleted file mode 100644 index c2812a25a..000000000 --- a/langfuse/api/resources/scim/types/scim_name.py +++ /dev/null @@ -1,42 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class ScimName(pydantic_v1.BaseModel): - formatted: typing.Optional[str] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/scim_user.py b/langfuse/api/resources/scim/types/scim_user.py deleted file mode 100644 index 581bab8c1..000000000 --- a/langfuse/api/resources/scim/types/scim_user.py +++ /dev/null @@ -1,52 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .scim_email import ScimEmail -from .scim_name import ScimName -from .user_meta import UserMeta - - -class ScimUser(pydantic_v1.BaseModel): - schemas: typing.List[str] - id: str - user_name: str = pydantic_v1.Field(alias="userName") - name: ScimName - emails: typing.List[ScimEmail] - meta: UserMeta - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/scim_users_list_response.py b/langfuse/api/resources/scim/types/scim_users_list_response.py deleted file mode 100644 index 3c41a4d16..000000000 --- a/langfuse/api/resources/scim/types/scim_users_list_response.py +++ /dev/null @@ -1,49 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .scim_user import ScimUser - - -class ScimUsersListResponse(pydantic_v1.BaseModel): - schemas: typing.List[str] - total_results: int = pydantic_v1.Field(alias="totalResults") - start_index: int = pydantic_v1.Field(alias="startIndex") - items_per_page: int = pydantic_v1.Field(alias="itemsPerPage") - resources: typing.List[ScimUser] = pydantic_v1.Field(alias="Resources") - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/service_provider_config.py b/langfuse/api/resources/scim/types/service_provider_config.py deleted file mode 100644 index 9bf611ae6..000000000 --- a/langfuse/api/resources/scim/types/service_provider_config.py +++ /dev/null @@ -1,60 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from .authentication_scheme import AuthenticationScheme -from .bulk_config import BulkConfig -from .filter_config import FilterConfig -from .resource_meta import ResourceMeta -from .scim_feature_support import ScimFeatureSupport - - -class ServiceProviderConfig(pydantic_v1.BaseModel): - schemas: typing.List[str] - documentation_uri: str = pydantic_v1.Field(alias="documentationUri") - patch: ScimFeatureSupport - bulk: BulkConfig - filter: FilterConfig - change_password: ScimFeatureSupport = pydantic_v1.Field(alias="changePassword") - sort: ScimFeatureSupport - etag: ScimFeatureSupport - authentication_schemes: typing.List[AuthenticationScheme] = pydantic_v1.Field( - alias="authenticationSchemes" - ) - meta: ResourceMeta - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/scim/types/user_meta.py b/langfuse/api/resources/scim/types/user_meta.py deleted file mode 100644 index 09cb7e6a0..000000000 --- a/langfuse/api/resources/scim/types/user_meta.py +++ /dev/null @@ -1,48 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class UserMeta(pydantic_v1.BaseModel): - resource_type: str = pydantic_v1.Field(alias="resourceType") - created: typing.Optional[str] = None - last_modified: typing.Optional[str] = pydantic_v1.Field( - alias="lastModified", default=None - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/score/__init__.py b/langfuse/api/resources/score/__init__.py deleted file mode 100644 index 566310af3..000000000 --- a/langfuse/api/resources/score/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import CreateScoreRequest, CreateScoreResponse - -__all__ = ["CreateScoreRequest", "CreateScoreResponse"] diff --git a/langfuse/api/resources/score/client.py b/langfuse/api/resources/score/client.py deleted file mode 100644 index 0c259929f..000000000 --- a/langfuse/api/resources/score/client.py +++ /dev/null @@ -1,322 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from .types.create_score_request import CreateScoreRequest -from .types.create_score_response import CreateScoreResponse - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class ScoreClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def create( - self, - *, - request: CreateScoreRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateScoreResponse: - """ - Create a score (supports both trace and session scores) - - Parameters - ---------- - request : CreateScoreRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateScoreResponse - - Examples - -------- - from langfuse import CreateScoreRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.score.create( - request=CreateScoreRequest( - name="name", - value=1.1, - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/scores", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(CreateScoreResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def delete( - self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Delete a score (supports both trace and session scores) - - Parameters - ---------- - score_id : str - The unique langfuse identifier of a score - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.score.delete( - score_id="scoreId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/scores/{jsonable_encoder(score_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncScoreClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def create( - self, - *, - request: CreateScoreRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> CreateScoreResponse: - """ - Create a score (supports both trace and session scores) - - Parameters - ---------- - request : CreateScoreRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - CreateScoreResponse - - Examples - -------- - import asyncio - - from langfuse import CreateScoreRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.score.create( - request=CreateScoreRequest( - name="name", - value=1.1, - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/scores", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(CreateScoreResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def delete( - self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> None: - """ - Delete a score (supports both trace and session scores) - - Parameters - ---------- - score_id : str - The unique langfuse identifier of a score - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - None - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.score.delete( - score_id="scoreId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/scores/{jsonable_encoder(score_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/score/types/__init__.py b/langfuse/api/resources/score/types/__init__.py deleted file mode 100644 index 72d61f6f3..000000000 --- a/langfuse/api/resources/score/types/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .create_score_request import CreateScoreRequest -from .create_score_response import CreateScoreResponse - -__all__ = ["CreateScoreRequest", "CreateScoreResponse"] diff --git a/langfuse/api/resources/score/types/create_score_request.py b/langfuse/api/resources/score/types/create_score_request.py deleted file mode 100644 index 1f79f4a64..000000000 --- a/langfuse/api/resources/score/types/create_score_request.py +++ /dev/null @@ -1,97 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.create_score_value import CreateScoreValue -from ...commons.types.score_data_type import ScoreDataType - - -class CreateScoreRequest(pydantic_v1.BaseModel): - """ - Examples - -------- - from langfuse import CreateScoreRequest - - CreateScoreRequest( - name="novelty", - value=0.9, - trace_id="cdef-1234-5678-90ab", - ) - """ - - id: typing.Optional[str] = None - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - session_id: typing.Optional[str] = pydantic_v1.Field( - alias="sessionId", default=None - ) - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - dataset_run_id: typing.Optional[str] = pydantic_v1.Field( - alias="datasetRunId", default=None - ) - name: str - value: CreateScoreValue = pydantic_v1.Field() - """ - The value of the score. Must be passed as string for categorical scores, and numeric for boolean and numeric scores. Boolean score values must equal either 1 or 0 (true or false) - """ - - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Dict[str, typing.Any]] = None - environment: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The environment of the score. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. - """ - - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - """ - The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. - """ - - data_type: typing.Optional[ScoreDataType] = pydantic_v1.Field( - alias="dataType", default=None - ) - """ - The data type of the score. When passing a configId this field is inferred. Otherwise, this field must be passed or will default to numeric. - """ - - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - """ - Reference a score config on a score. The unique langfuse identifier of a score config. When passing this field, the dataType and stringValue fields are automatically populated. - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/score/types/create_score_response.py b/langfuse/api/resources/score/types/create_score_response.py deleted file mode 100644 index a8c90fce2..000000000 --- a/langfuse/api/resources/score/types/create_score_response.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class CreateScoreResponse(pydantic_v1.BaseModel): - id: str = pydantic_v1.Field() - """ - The id of the created object in Langfuse - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/score_configs/__init__.py b/langfuse/api/resources/score_configs/__init__.py deleted file mode 100644 index da401d35d..000000000 --- a/langfuse/api/resources/score_configs/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import CreateScoreConfigRequest, ScoreConfigs, UpdateScoreConfigRequest - -__all__ = ["CreateScoreConfigRequest", "ScoreConfigs", "UpdateScoreConfigRequest"] diff --git a/langfuse/api/resources/score_configs/client.py b/langfuse/api/resources/score_configs/client.py deleted file mode 100644 index 7faea8312..000000000 --- a/langfuse/api/resources/score_configs/client.py +++ /dev/null @@ -1,632 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from ..commons.types.score_config import ScoreConfig -from .types.create_score_config_request import CreateScoreConfigRequest -from .types.score_configs import ScoreConfigs -from .types.update_score_config_request import UpdateScoreConfigRequest - -# this is used as the default value for optional parameters -OMIT = typing.cast(typing.Any, ...) - - -class ScoreConfigsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def create( - self, - *, - request: CreateScoreConfigRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> ScoreConfig: - """ - Create a score configuration (config). Score configs are used to define the structure of scores - - Parameters - ---------- - request : CreateScoreConfigRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScoreConfig - - Examples - -------- - from langfuse import CreateScoreConfigRequest, ScoreDataType - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.score_configs.create( - request=CreateScoreConfigRequest( - name="name", - data_type=ScoreDataType.NUMERIC, - ), - ) - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/score-configs", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScoreConfig, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> ScoreConfigs: - """ - Get all score configs - - Parameters - ---------- - page : typing.Optional[int] - Page number, starts at 1. - - limit : typing.Optional[int] - Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScoreConfigs - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.score_configs.get() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/score-configs", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScoreConfigs, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get_by_id( - self, config_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ScoreConfig: - """ - Get a score config - - Parameters - ---------- - config_id : str - The unique langfuse identifier of a score config - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScoreConfig - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.score_configs.get_by_id( - config_id="configId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/score-configs/{jsonable_encoder(config_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScoreConfig, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def update( - self, - config_id: str, - *, - request: UpdateScoreConfigRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> ScoreConfig: - """ - Update a score config - - Parameters - ---------- - config_id : str - The unique langfuse identifier of a score config - - request : UpdateScoreConfigRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScoreConfig - - Examples - -------- - from langfuse import UpdateScoreConfigRequest - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.score_configs.update( - config_id="configId", - request=UpdateScoreConfigRequest(), - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/score-configs/{jsonable_encoder(config_id)}", - method="PATCH", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScoreConfig, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncScoreConfigsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def create( - self, - *, - request: CreateScoreConfigRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> ScoreConfig: - """ - Create a score configuration (config). Score configs are used to define the structure of scores - - Parameters - ---------- - request : CreateScoreConfigRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScoreConfig - - Examples - -------- - import asyncio - - from langfuse import CreateScoreConfigRequest, ScoreDataType - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.score_configs.create( - request=CreateScoreConfigRequest( - name="name", - data_type=ScoreDataType.NUMERIC, - ), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/score-configs", - method="POST", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScoreConfig, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> ScoreConfigs: - """ - Get all score configs - - Parameters - ---------- - page : typing.Optional[int] - Page number, starts at 1. - - limit : typing.Optional[int] - Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScoreConfigs - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.score_configs.get() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/score-configs", - method="GET", - params={"page": page, "limit": limit}, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScoreConfigs, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get_by_id( - self, config_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> ScoreConfig: - """ - Get a score config - - Parameters - ---------- - config_id : str - The unique langfuse identifier of a score config - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScoreConfig - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.score_configs.get_by_id( - config_id="configId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/score-configs/{jsonable_encoder(config_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScoreConfig, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def update( - self, - config_id: str, - *, - request: UpdateScoreConfigRequest, - request_options: typing.Optional[RequestOptions] = None, - ) -> ScoreConfig: - """ - Update a score config - - Parameters - ---------- - config_id : str - The unique langfuse identifier of a score config - - request : UpdateScoreConfigRequest - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - ScoreConfig - - Examples - -------- - import asyncio - - from langfuse import UpdateScoreConfigRequest - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.score_configs.update( - config_id="configId", - request=UpdateScoreConfigRequest(), - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/score-configs/{jsonable_encoder(config_id)}", - method="PATCH", - json=request, - request_options=request_options, - omit=OMIT, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(ScoreConfig, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/score_configs/types/__init__.py b/langfuse/api/resources/score_configs/types/__init__.py deleted file mode 100644 index 1c328b614..000000000 --- a/langfuse/api/resources/score_configs/types/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .create_score_config_request import CreateScoreConfigRequest -from .score_configs import ScoreConfigs -from .update_score_config_request import UpdateScoreConfigRequest - -__all__ = ["CreateScoreConfigRequest", "ScoreConfigs", "UpdateScoreConfigRequest"] diff --git a/langfuse/api/resources/score_configs/types/create_score_config_request.py b/langfuse/api/resources/score_configs/types/create_score_config_request.py deleted file mode 100644 index e136af157..000000000 --- a/langfuse/api/resources/score_configs/types/create_score_config_request.py +++ /dev/null @@ -1,72 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.config_category import ConfigCategory -from ...commons.types.score_data_type import ScoreDataType - - -class CreateScoreConfigRequest(pydantic_v1.BaseModel): - name: str - data_type: ScoreDataType = pydantic_v1.Field(alias="dataType") - categories: typing.Optional[typing.List[ConfigCategory]] = pydantic_v1.Field( - default=None - ) - """ - Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed - """ - - min_value: typing.Optional[float] = pydantic_v1.Field( - alias="minValue", default=None - ) - """ - Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ - """ - - max_value: typing.Optional[float] = pydantic_v1.Field( - alias="maxValue", default=None - ) - """ - Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ - """ - - description: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/score_configs/types/score_configs.py b/langfuse/api/resources/score_configs/types/score_configs.py deleted file mode 100644 index fc84e28a3..000000000 --- a/langfuse/api/resources/score_configs/types/score_configs.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.score_config import ScoreConfig -from ...utils.resources.pagination.types.meta_response import MetaResponse - - -class ScoreConfigs(pydantic_v1.BaseModel): - data: typing.List[ScoreConfig] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/score_configs/types/update_score_config_request.py b/langfuse/api/resources/score_configs/types/update_score_config_request.py deleted file mode 100644 index ce5f980b8..000000000 --- a/langfuse/api/resources/score_configs/types/update_score_config_request.py +++ /dev/null @@ -1,81 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.config_category import ConfigCategory - - -class UpdateScoreConfigRequest(pydantic_v1.BaseModel): - is_archived: typing.Optional[bool] = pydantic_v1.Field( - alias="isArchived", default=None - ) - """ - The status of the score config showing if it is archived or not - """ - - name: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The name of the score config - """ - - categories: typing.Optional[typing.List[ConfigCategory]] = pydantic_v1.Field( - default=None - ) - """ - Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed - """ - - min_value: typing.Optional[float] = pydantic_v1.Field( - alias="minValue", default=None - ) - """ - Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ - """ - - max_value: typing.Optional[float] = pydantic_v1.Field( - alias="maxValue", default=None - ) - """ - Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ - """ - - description: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/score_v_2/__init__.py b/langfuse/api/resources/score_v_2/__init__.py deleted file mode 100644 index 40599eec1..000000000 --- a/langfuse/api/resources/score_v_2/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import ( - GetScoresResponse, - GetScoresResponseData, - GetScoresResponseDataBoolean, - GetScoresResponseDataCategorical, - GetScoresResponseDataNumeric, - GetScoresResponseData_Boolean, - GetScoresResponseData_Categorical, - GetScoresResponseData_Numeric, - GetScoresResponseTraceData, -) - -__all__ = [ - "GetScoresResponse", - "GetScoresResponseData", - "GetScoresResponseDataBoolean", - "GetScoresResponseDataCategorical", - "GetScoresResponseDataNumeric", - "GetScoresResponseData_Boolean", - "GetScoresResponseData_Categorical", - "GetScoresResponseData_Numeric", - "GetScoresResponseTraceData", -] diff --git a/langfuse/api/resources/score_v_2/types/__init__.py b/langfuse/api/resources/score_v_2/types/__init__.py deleted file mode 100644 index 480ed3406..000000000 --- a/langfuse/api/resources/score_v_2/types/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .get_scores_response import GetScoresResponse -from .get_scores_response_data import ( - GetScoresResponseData, - GetScoresResponseData_Boolean, - GetScoresResponseData_Categorical, - GetScoresResponseData_Numeric, -) -from .get_scores_response_data_boolean import GetScoresResponseDataBoolean -from .get_scores_response_data_categorical import GetScoresResponseDataCategorical -from .get_scores_response_data_numeric import GetScoresResponseDataNumeric -from .get_scores_response_trace_data import GetScoresResponseTraceData - -__all__ = [ - "GetScoresResponse", - "GetScoresResponseData", - "GetScoresResponseDataBoolean", - "GetScoresResponseDataCategorical", - "GetScoresResponseDataNumeric", - "GetScoresResponseData_Boolean", - "GetScoresResponseData_Categorical", - "GetScoresResponseData_Numeric", - "GetScoresResponseTraceData", -] diff --git a/langfuse/api/resources/score_v_2/types/get_scores_response.py b/langfuse/api/resources/score_v_2/types/get_scores_response.py deleted file mode 100644 index 777bb799b..000000000 --- a/langfuse/api/resources/score_v_2/types/get_scores_response.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...utils.resources.pagination.types.meta_response import MetaResponse -from .get_scores_response_data import GetScoresResponseData - - -class GetScoresResponse(pydantic_v1.BaseModel): - data: typing.List[GetScoresResponseData] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/score_v_2/types/get_scores_response_data.py b/langfuse/api/resources/score_v_2/types/get_scores_response_data.py deleted file mode 100644 index e09f31cb9..000000000 --- a/langfuse/api/resources/score_v_2/types/get_scores_response_data.py +++ /dev/null @@ -1,215 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from __future__ import annotations - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.score_source import ScoreSource -from .get_scores_response_trace_data import GetScoresResponseTraceData - - -class GetScoresResponseData_Numeric(pydantic_v1.BaseModel): - trace: typing.Optional[GetScoresResponseTraceData] = None - value: float - id: str - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - session_id: typing.Optional[str] = pydantic_v1.Field( - alias="sessionId", default=None - ) - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - dataset_run_id: typing.Optional[str] = pydantic_v1.Field( - alias="datasetRunId", default=None - ) - name: str - source: ScoreSource - timestamp: dt.datetime - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - environment: typing.Optional[str] = None - data_type: typing.Literal["NUMERIC"] = pydantic_v1.Field( - alias="dataType", default="NUMERIC" - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class GetScoresResponseData_Categorical(pydantic_v1.BaseModel): - trace: typing.Optional[GetScoresResponseTraceData] = None - value: float - string_value: str = pydantic_v1.Field(alias="stringValue") - id: str - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - session_id: typing.Optional[str] = pydantic_v1.Field( - alias="sessionId", default=None - ) - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - dataset_run_id: typing.Optional[str] = pydantic_v1.Field( - alias="datasetRunId", default=None - ) - name: str - source: ScoreSource - timestamp: dt.datetime - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - environment: typing.Optional[str] = None - data_type: typing.Literal["CATEGORICAL"] = pydantic_v1.Field( - alias="dataType", default="CATEGORICAL" - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -class GetScoresResponseData_Boolean(pydantic_v1.BaseModel): - trace: typing.Optional[GetScoresResponseTraceData] = None - value: float - string_value: str = pydantic_v1.Field(alias="stringValue") - id: str - trace_id: typing.Optional[str] = pydantic_v1.Field(alias="traceId", default=None) - session_id: typing.Optional[str] = pydantic_v1.Field( - alias="sessionId", default=None - ) - observation_id: typing.Optional[str] = pydantic_v1.Field( - alias="observationId", default=None - ) - dataset_run_id: typing.Optional[str] = pydantic_v1.Field( - alias="datasetRunId", default=None - ) - name: str - source: ScoreSource - timestamp: dt.datetime - created_at: dt.datetime = pydantic_v1.Field(alias="createdAt") - updated_at: dt.datetime = pydantic_v1.Field(alias="updatedAt") - author_user_id: typing.Optional[str] = pydantic_v1.Field( - alias="authorUserId", default=None - ) - comment: typing.Optional[str] = None - metadata: typing.Optional[typing.Any] = None - config_id: typing.Optional[str] = pydantic_v1.Field(alias="configId", default=None) - queue_id: typing.Optional[str] = pydantic_v1.Field(alias="queueId", default=None) - environment: typing.Optional[str] = None - data_type: typing.Literal["BOOLEAN"] = pydantic_v1.Field( - alias="dataType", default="BOOLEAN" - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} - - -GetScoresResponseData = typing.Union[ - GetScoresResponseData_Numeric, - GetScoresResponseData_Categorical, - GetScoresResponseData_Boolean, -] diff --git a/langfuse/api/resources/score_v_2/types/get_scores_response_data_boolean.py b/langfuse/api/resources/score_v_2/types/get_scores_response_data_boolean.py deleted file mode 100644 index 48012990c..000000000 --- a/langfuse/api/resources/score_v_2/types/get_scores_response_data_boolean.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.boolean_score import BooleanScore -from .get_scores_response_trace_data import GetScoresResponseTraceData - - -class GetScoresResponseDataBoolean(BooleanScore): - trace: typing.Optional[GetScoresResponseTraceData] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/score_v_2/types/get_scores_response_data_categorical.py b/langfuse/api/resources/score_v_2/types/get_scores_response_data_categorical.py deleted file mode 100644 index 6e27f6d64..000000000 --- a/langfuse/api/resources/score_v_2/types/get_scores_response_data_categorical.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.categorical_score import CategoricalScore -from .get_scores_response_trace_data import GetScoresResponseTraceData - - -class GetScoresResponseDataCategorical(CategoricalScore): - trace: typing.Optional[GetScoresResponseTraceData] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/score_v_2/types/get_scores_response_data_numeric.py b/langfuse/api/resources/score_v_2/types/get_scores_response_data_numeric.py deleted file mode 100644 index f7342833f..000000000 --- a/langfuse/api/resources/score_v_2/types/get_scores_response_data_numeric.py +++ /dev/null @@ -1,46 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.numeric_score import NumericScore -from .get_scores_response_trace_data import GetScoresResponseTraceData - - -class GetScoresResponseDataNumeric(NumericScore): - trace: typing.Optional[GetScoresResponseTraceData] = None - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/score_v_2/types/get_scores_response_trace_data.py b/langfuse/api/resources/score_v_2/types/get_scores_response_trace_data.py deleted file mode 100644 index 6e5539e35..000000000 --- a/langfuse/api/resources/score_v_2/types/get_scores_response_trace_data.py +++ /dev/null @@ -1,57 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class GetScoresResponseTraceData(pydantic_v1.BaseModel): - user_id: typing.Optional[str] = pydantic_v1.Field(alias="userId", default=None) - """ - The user ID associated with the trace referenced by score - """ - - tags: typing.Optional[typing.List[str]] = pydantic_v1.Field(default=None) - """ - A list of tags associated with the trace referenced by score - """ - - environment: typing.Optional[str] = pydantic_v1.Field(default=None) - """ - The environment of the trace referenced by score - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/sessions/__init__.py b/langfuse/api/resources/sessions/__init__.py deleted file mode 100644 index 048704297..000000000 --- a/langfuse/api/resources/sessions/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import PaginatedSessions - -__all__ = ["PaginatedSessions"] diff --git a/langfuse/api/resources/sessions/client.py b/langfuse/api/resources/sessions/client.py deleted file mode 100644 index d5ae779c3..000000000 --- a/langfuse/api/resources/sessions/client.py +++ /dev/null @@ -1,367 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.datetime_utils import serialize_datetime -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError -from ..commons.types.session_with_traces import SessionWithTraces -from .types.paginated_sessions import PaginatedSessions - - -class SessionsClient: - def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper - - def list( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - from_timestamp: typing.Optional[dt.datetime] = None, - to_timestamp: typing.Optional[dt.datetime] = None, - environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedSessions: - """ - Get sessions - - Parameters - ---------- - page : typing.Optional[int] - Page number, starts at 1 - - limit : typing.Optional[int] - Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. - - from_timestamp : typing.Optional[dt.datetime] - Optional filter to only include sessions created on or after a certain datetime (ISO 8601) - - to_timestamp : typing.Optional[dt.datetime] - Optional filter to only include sessions created before a certain datetime (ISO 8601) - - environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] - Optional filter for sessions where the environment is one of the provided values. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedSessions - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.sessions.list() - """ - _response = self._client_wrapper.httpx_client.request( - "api/public/sessions", - method="GET", - params={ - "page": page, - "limit": limit, - "fromTimestamp": serialize_datetime(from_timestamp) - if from_timestamp is not None - else None, - "toTimestamp": serialize_datetime(to_timestamp) - if to_timestamp is not None - else None, - "environment": environment, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(PaginatedSessions, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - def get( - self, - session_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> SessionWithTraces: - """ - Get a session. Please note that `traces` on this endpoint are not paginated, if you plan to fetch large sessions, consider `GET /api/public/traces?sessionId=` - - Parameters - ---------- - session_id : str - The unique id of a session - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SessionWithTraces - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.sessions.get( - session_id="sessionId", - ) - """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/sessions/{jsonable_encoder(session_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(SessionWithTraces, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - -class AsyncSessionsClient: - def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper - - async def list( - self, - *, - page: typing.Optional[int] = None, - limit: typing.Optional[int] = None, - from_timestamp: typing.Optional[dt.datetime] = None, - to_timestamp: typing.Optional[dt.datetime] = None, - environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, - request_options: typing.Optional[RequestOptions] = None, - ) -> PaginatedSessions: - """ - Get sessions - - Parameters - ---------- - page : typing.Optional[int] - Page number, starts at 1 - - limit : typing.Optional[int] - Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. - - from_timestamp : typing.Optional[dt.datetime] - Optional filter to only include sessions created on or after a certain datetime (ISO 8601) - - to_timestamp : typing.Optional[dt.datetime] - Optional filter to only include sessions created before a certain datetime (ISO 8601) - - environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] - Optional filter for sessions where the environment is one of the provided values. - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - PaginatedSessions - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.sessions.list() - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/sessions", - method="GET", - params={ - "page": page, - "limit": limit, - "fromTimestamp": serialize_datetime(from_timestamp) - if from_timestamp is not None - else None, - "toTimestamp": serialize_datetime(to_timestamp) - if to_timestamp is not None - else None, - "environment": environment, - }, - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(PaginatedSessions, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) - - async def get( - self, - session_id: str, - *, - request_options: typing.Optional[RequestOptions] = None, - ) -> SessionWithTraces: - """ - Get a session. Please note that `traces` on this endpoint are not paginated, if you plan to fetch large sessions, consider `GET /api/public/traces?sessionId=` - - Parameters - ---------- - session_id : str - The unique id of a session - - request_options : typing.Optional[RequestOptions] - Request-specific configuration. - - Returns - ------- - SessionWithTraces - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.sessions.get( - session_id="sessionId", - ) - - - asyncio.run(main()) - """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/sessions/{jsonable_encoder(session_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(SessionWithTraces, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) diff --git a/langfuse/api/resources/sessions/types/__init__.py b/langfuse/api/resources/sessions/types/__init__.py deleted file mode 100644 index 42d63b428..000000000 --- a/langfuse/api/resources/sessions/types/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .paginated_sessions import PaginatedSessions - -__all__ = ["PaginatedSessions"] diff --git a/langfuse/api/resources/sessions/types/paginated_sessions.py b/langfuse/api/resources/sessions/types/paginated_sessions.py deleted file mode 100644 index 5dd9fb497..000000000 --- a/langfuse/api/resources/sessions/types/paginated_sessions.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.session import Session -from ...utils.resources.pagination.types.meta_response import MetaResponse - - -class PaginatedSessions(pydantic_v1.BaseModel): - data: typing.List[Session] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/trace/__init__.py b/langfuse/api/resources/trace/__init__.py deleted file mode 100644 index 17855e971..000000000 --- a/langfuse/api/resources/trace/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .types import DeleteTraceResponse, Sort, Traces - -__all__ = ["DeleteTraceResponse", "Sort", "Traces"] diff --git a/langfuse/api/resources/trace/types/__init__.py b/langfuse/api/resources/trace/types/__init__.py deleted file mode 100644 index 929a1e047..000000000 --- a/langfuse/api/resources/trace/types/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .delete_trace_response import DeleteTraceResponse -from .sort import Sort -from .traces import Traces - -__all__ = ["DeleteTraceResponse", "Sort", "Traces"] diff --git a/langfuse/api/resources/trace/types/delete_trace_response.py b/langfuse/api/resources/trace/types/delete_trace_response.py deleted file mode 100644 index 450c894e2..000000000 --- a/langfuse/api/resources/trace/types/delete_trace_response.py +++ /dev/null @@ -1,42 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class DeleteTraceResponse(pydantic_v1.BaseModel): - message: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/trace/types/sort.py b/langfuse/api/resources/trace/types/sort.py deleted file mode 100644 index 76a5045b6..000000000 --- a/langfuse/api/resources/trace/types/sort.py +++ /dev/null @@ -1,42 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class Sort(pydantic_v1.BaseModel): - id: str - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/trace/types/traces.py b/langfuse/api/resources/trace/types/traces.py deleted file mode 100644 index 09f58978f..000000000 --- a/langfuse/api/resources/trace/types/traces.py +++ /dev/null @@ -1,45 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ....core.datetime_utils import serialize_datetime -from ....core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 -from ...commons.types.trace_with_details import TraceWithDetails -from ...utils.resources.pagination.types.meta_response import MetaResponse - - -class Traces(pydantic_v1.BaseModel): - data: typing.List[TraceWithDetails] - meta: MetaResponse - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/resources/utils/__init__.py b/langfuse/api/resources/utils/__init__.py deleted file mode 100644 index b4ac87b8a..000000000 --- a/langfuse/api/resources/utils/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .resources import MetaResponse, pagination - -__all__ = ["MetaResponse", "pagination"] diff --git a/langfuse/api/resources/utils/resources/__init__.py b/langfuse/api/resources/utils/resources/__init__.py deleted file mode 100644 index 7e65ff270..000000000 --- a/langfuse/api/resources/utils/resources/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from . import pagination -from .pagination import MetaResponse - -__all__ = ["MetaResponse", "pagination"] diff --git a/langfuse/api/resources/utils/resources/pagination/types/__init__.py b/langfuse/api/resources/utils/resources/pagination/types/__init__.py deleted file mode 100644 index 79bb6018e..000000000 --- a/langfuse/api/resources/utils/resources/pagination/types/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -from .meta_response import MetaResponse - -__all__ = ["MetaResponse"] diff --git a/langfuse/api/resources/utils/resources/pagination/types/meta_response.py b/langfuse/api/resources/utils/resources/pagination/types/meta_response.py deleted file mode 100644 index 2d082c68f..000000000 --- a/langfuse/api/resources/utils/resources/pagination/types/meta_response.py +++ /dev/null @@ -1,62 +0,0 @@ -# This file was auto-generated by Fern from our API Definition. - -import datetime as dt -import typing - -from ......core.datetime_utils import serialize_datetime -from ......core.pydantic_utilities import deep_union_pydantic_dicts, pydantic_v1 - - -class MetaResponse(pydantic_v1.BaseModel): - page: int = pydantic_v1.Field() - """ - current page number - """ - - limit: int = pydantic_v1.Field() - """ - number of items per page - """ - - total_items: int = pydantic_v1.Field(alias="totalItems") - """ - number of total items given the current filters/selection (if any) - """ - - total_pages: int = pydantic_v1.Field(alias="totalPages") - """ - number of total pages given the current limit - """ - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults_exclude_unset: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - kwargs_with_defaults_exclude_none: typing.Any = { - "by_alias": True, - "exclude_none": True, - **kwargs, - } - - return deep_union_pydantic_dicts( - super().dict(**kwargs_with_defaults_exclude_unset), - super().dict(**kwargs_with_defaults_exclude_none), - ) - - class Config: - frozen = True - smart_union = True - allow_population_by_field_name = True - populate_by_name = True - extra = pydantic_v1.Extra.allow - json_encoders = {dt.datetime: serialize_datetime} diff --git a/langfuse/api/scim/__init__.py b/langfuse/api/scim/__init__.py new file mode 100644 index 000000000..6c4126f3c --- /dev/null +++ b/langfuse/api/scim/__init__.py @@ -0,0 +1,94 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + AuthenticationScheme, + BulkConfig, + EmptyResponse, + FilterConfig, + ResourceMeta, + ResourceType, + ResourceTypesResponse, + SchemaExtension, + SchemaResource, + SchemasResponse, + ScimEmail, + ScimFeatureSupport, + ScimName, + ScimUser, + ScimUsersListResponse, + ServiceProviderConfig, + UserMeta, + ) +_dynamic_imports: typing.Dict[str, str] = { + "AuthenticationScheme": ".types", + "BulkConfig": ".types", + "EmptyResponse": ".types", + "FilterConfig": ".types", + "ResourceMeta": ".types", + "ResourceType": ".types", + "ResourceTypesResponse": ".types", + "SchemaExtension": ".types", + "SchemaResource": ".types", + "SchemasResponse": ".types", + "ScimEmail": ".types", + "ScimFeatureSupport": ".types", + "ScimName": ".types", + "ScimUser": ".types", + "ScimUsersListResponse": ".types", + "ServiceProviderConfig": ".types", + "UserMeta": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "AuthenticationScheme", + "BulkConfig", + "EmptyResponse", + "FilterConfig", + "ResourceMeta", + "ResourceType", + "ResourceTypesResponse", + "SchemaExtension", + "SchemaResource", + "SchemasResponse", + "ScimEmail", + "ScimFeatureSupport", + "ScimName", + "ScimUser", + "ScimUsersListResponse", + "ServiceProviderConfig", + "UserMeta", +] diff --git a/langfuse/api/scim/client.py b/langfuse/api/scim/client.py new file mode 100644 index 000000000..30d0815bf --- /dev/null +++ b/langfuse/api/scim/client.py @@ -0,0 +1,686 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawScimClient, RawScimClient +from .types.empty_response import EmptyResponse +from .types.resource_types_response import ResourceTypesResponse +from .types.schemas_response import SchemasResponse +from .types.scim_email import ScimEmail +from .types.scim_name import ScimName +from .types.scim_user import ScimUser +from .types.scim_users_list_response import ScimUsersListResponse +from .types.service_provider_config import ServiceProviderConfig + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class ScimClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawScimClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawScimClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawScimClient + """ + return self._raw_client + + def get_service_provider_config( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> ServiceProviderConfig: + """ + Get SCIM Service Provider Configuration (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ServiceProviderConfig + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.scim.get_service_provider_config() + """ + _response = self._raw_client.get_service_provider_config( + request_options=request_options + ) + return _response.data + + def get_resource_types( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> ResourceTypesResponse: + """ + Get SCIM Resource Types (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ResourceTypesResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.scim.get_resource_types() + """ + _response = self._raw_client.get_resource_types(request_options=request_options) + return _response.data + + def get_schemas( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> SchemasResponse: + """ + Get SCIM Schemas (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SchemasResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.scim.get_schemas() + """ + _response = self._raw_client.get_schemas(request_options=request_options) + return _response.data + + def list_users( + self, + *, + filter: typing.Optional[str] = None, + start_index: typing.Optional[int] = None, + count: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ScimUsersListResponse: + """ + List users in the organization (requires organization-scoped API key) + + Parameters + ---------- + filter : typing.Optional[str] + Filter expression (e.g. userName eq "value") + + start_index : typing.Optional[int] + 1-based index of the first result to return (default 1) + + count : typing.Optional[int] + Maximum number of results to return (default 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScimUsersListResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.scim.list_users() + """ + _response = self._raw_client.list_users( + filter=filter, + start_index=start_index, + count=count, + request_options=request_options, + ) + return _response.data + + def create_user( + self, + *, + user_name: str, + name: ScimName, + emails: typing.Optional[typing.Sequence[ScimEmail]] = OMIT, + active: typing.Optional[bool] = OMIT, + password: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> ScimUser: + """ + Create a new user in the organization (requires organization-scoped API key) + + Parameters + ---------- + user_name : str + User's email address (required) + + name : ScimName + User's name information + + emails : typing.Optional[typing.Sequence[ScimEmail]] + User's email addresses + + active : typing.Optional[bool] + Whether the user is active + + password : typing.Optional[str] + Initial password for the user + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScimUser + + Examples + -------- + from langfuse import LangfuseAPI + from langfuse.scim import ScimName + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.scim.create_user( + user_name="userName", + name=ScimName(), + ) + """ + _response = self._raw_client.create_user( + user_name=user_name, + name=name, + emails=emails, + active=active, + password=password, + request_options=request_options, + ) + return _response.data + + def get_user( + self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> ScimUser: + """ + Get a specific user by ID (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScimUser + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.scim.get_user( + user_id="userId", + ) + """ + _response = self._raw_client.get_user(user_id, request_options=request_options) + return _response.data + + def delete_user( + self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> EmptyResponse: + """ + Remove a user from the organization (requires organization-scoped API key). Note that this only removes the user from the organization but does not delete the user entity itself. + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + EmptyResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.scim.delete_user( + user_id="userId", + ) + """ + _response = self._raw_client.delete_user( + user_id, request_options=request_options + ) + return _response.data + + +class AsyncScimClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawScimClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawScimClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawScimClient + """ + return self._raw_client + + async def get_service_provider_config( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> ServiceProviderConfig: + """ + Get SCIM Service Provider Configuration (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ServiceProviderConfig + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.scim.get_service_provider_config() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_service_provider_config( + request_options=request_options + ) + return _response.data + + async def get_resource_types( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> ResourceTypesResponse: + """ + Get SCIM Resource Types (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ResourceTypesResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.scim.get_resource_types() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_resource_types( + request_options=request_options + ) + return _response.data + + async def get_schemas( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> SchemasResponse: + """ + Get SCIM Schemas (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SchemasResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.scim.get_schemas() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_schemas(request_options=request_options) + return _response.data + + async def list_users( + self, + *, + filter: typing.Optional[str] = None, + start_index: typing.Optional[int] = None, + count: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ScimUsersListResponse: + """ + List users in the organization (requires organization-scoped API key) + + Parameters + ---------- + filter : typing.Optional[str] + Filter expression (e.g. userName eq "value") + + start_index : typing.Optional[int] + 1-based index of the first result to return (default 1) + + count : typing.Optional[int] + Maximum number of results to return (default 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScimUsersListResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.scim.list_users() + + + asyncio.run(main()) + """ + _response = await self._raw_client.list_users( + filter=filter, + start_index=start_index, + count=count, + request_options=request_options, + ) + return _response.data + + async def create_user( + self, + *, + user_name: str, + name: ScimName, + emails: typing.Optional[typing.Sequence[ScimEmail]] = OMIT, + active: typing.Optional[bool] = OMIT, + password: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> ScimUser: + """ + Create a new user in the organization (requires organization-scoped API key) + + Parameters + ---------- + user_name : str + User's email address (required) + + name : ScimName + User's name information + + emails : typing.Optional[typing.Sequence[ScimEmail]] + User's email addresses + + active : typing.Optional[bool] + Whether the user is active + + password : typing.Optional[str] + Initial password for the user + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScimUser + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + from langfuse.scim import ScimName + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.scim.create_user( + user_name="userName", + name=ScimName(), + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create_user( + user_name=user_name, + name=name, + emails=emails, + active=active, + password=password, + request_options=request_options, + ) + return _response.data + + async def get_user( + self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> ScimUser: + """ + Get a specific user by ID (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScimUser + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.scim.get_user( + user_id="userId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_user( + user_id, request_options=request_options + ) + return _response.data + + async def delete_user( + self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> EmptyResponse: + """ + Remove a user from the organization (requires organization-scoped API key). Note that this only removes the user from the organization but does not delete the user entity itself. + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + EmptyResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.scim.delete_user( + user_id="userId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete_user( + user_id, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/scim/raw_client.py b/langfuse/api/scim/raw_client.py new file mode 100644 index 000000000..e65f46592 --- /dev/null +++ b/langfuse/api/scim/raw_client.py @@ -0,0 +1,1528 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from ..core.serialization import convert_and_respect_annotation_metadata +from .types.empty_response import EmptyResponse +from .types.resource_types_response import ResourceTypesResponse +from .types.schemas_response import SchemasResponse +from .types.scim_email import ScimEmail +from .types.scim_name import ScimName +from .types.scim_user import ScimUser +from .types.scim_users_list_response import ScimUsersListResponse +from .types.service_provider_config import ServiceProviderConfig + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawScimClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get_service_provider_config( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[ServiceProviderConfig]: + """ + Get SCIM Service Provider Configuration (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ServiceProviderConfig] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/scim/ServiceProviderConfig", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ServiceProviderConfig, + parse_obj_as( + type_=ServiceProviderConfig, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_resource_types( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[ResourceTypesResponse]: + """ + Get SCIM Resource Types (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ResourceTypesResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/scim/ResourceTypes", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ResourceTypesResponse, + parse_obj_as( + type_=ResourceTypesResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_schemas( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[SchemasResponse]: + """ + Get SCIM Schemas (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[SchemasResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/scim/Schemas", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + SchemasResponse, + parse_obj_as( + type_=SchemasResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def list_users( + self, + *, + filter: typing.Optional[str] = None, + start_index: typing.Optional[int] = None, + count: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ScimUsersListResponse]: + """ + List users in the organization (requires organization-scoped API key) + + Parameters + ---------- + filter : typing.Optional[str] + Filter expression (e.g. userName eq "value") + + start_index : typing.Optional[int] + 1-based index of the first result to return (default 1) + + count : typing.Optional[int] + Maximum number of results to return (default 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ScimUsersListResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/scim/Users", + method="GET", + params={ + "filter": filter, + "startIndex": start_index, + "count": count, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScimUsersListResponse, + parse_obj_as( + type_=ScimUsersListResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def create_user( + self, + *, + user_name: str, + name: ScimName, + emails: typing.Optional[typing.Sequence[ScimEmail]] = OMIT, + active: typing.Optional[bool] = OMIT, + password: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ScimUser]: + """ + Create a new user in the organization (requires organization-scoped API key) + + Parameters + ---------- + user_name : str + User's email address (required) + + name : ScimName + User's name information + + emails : typing.Optional[typing.Sequence[ScimEmail]] + User's email addresses + + active : typing.Optional[bool] + Whether the user is active + + password : typing.Optional[str] + Initial password for the user + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ScimUser] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/scim/Users", + method="POST", + json={ + "userName": user_name, + "name": convert_and_respect_annotation_metadata( + object_=name, annotation=ScimName, direction="write" + ), + "emails": convert_and_respect_annotation_metadata( + object_=emails, + annotation=typing.Sequence[ScimEmail], + direction="write", + ), + "active": active, + "password": password, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScimUser, + parse_obj_as( + type_=ScimUser, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_user( + self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[ScimUser]: + """ + Get a specific user by ID (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ScimUser] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/scim/Users/{jsonable_encoder(user_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScimUser, + parse_obj_as( + type_=ScimUser, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete_user( + self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[EmptyResponse]: + """ + Remove a user from the organization (requires organization-scoped API key). Note that this only removes the user from the organization but does not delete the user entity itself. + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[EmptyResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/scim/Users/{jsonable_encoder(user_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + EmptyResponse, + parse_obj_as( + type_=EmptyResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawScimClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get_service_provider_config( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[ServiceProviderConfig]: + """ + Get SCIM Service Provider Configuration (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ServiceProviderConfig] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/scim/ServiceProviderConfig", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ServiceProviderConfig, + parse_obj_as( + type_=ServiceProviderConfig, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_resource_types( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[ResourceTypesResponse]: + """ + Get SCIM Resource Types (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ResourceTypesResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/scim/ResourceTypes", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ResourceTypesResponse, + parse_obj_as( + type_=ResourceTypesResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_schemas( + self, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[SchemasResponse]: + """ + Get SCIM Schemas (requires organization-scoped API key) + + Parameters + ---------- + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[SchemasResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/scim/Schemas", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + SchemasResponse, + parse_obj_as( + type_=SchemasResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def list_users( + self, + *, + filter: typing.Optional[str] = None, + start_index: typing.Optional[int] = None, + count: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ScimUsersListResponse]: + """ + List users in the organization (requires organization-scoped API key) + + Parameters + ---------- + filter : typing.Optional[str] + Filter expression (e.g. userName eq "value") + + start_index : typing.Optional[int] + 1-based index of the first result to return (default 1) + + count : typing.Optional[int] + Maximum number of results to return (default 100) + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ScimUsersListResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/scim/Users", + method="GET", + params={ + "filter": filter, + "startIndex": start_index, + "count": count, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScimUsersListResponse, + parse_obj_as( + type_=ScimUsersListResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def create_user( + self, + *, + user_name: str, + name: ScimName, + emails: typing.Optional[typing.Sequence[ScimEmail]] = OMIT, + active: typing.Optional[bool] = OMIT, + password: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ScimUser]: + """ + Create a new user in the organization (requires organization-scoped API key) + + Parameters + ---------- + user_name : str + User's email address (required) + + name : ScimName + User's name information + + emails : typing.Optional[typing.Sequence[ScimEmail]] + User's email addresses + + active : typing.Optional[bool] + Whether the user is active + + password : typing.Optional[str] + Initial password for the user + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ScimUser] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/scim/Users", + method="POST", + json={ + "userName": user_name, + "name": convert_and_respect_annotation_metadata( + object_=name, annotation=ScimName, direction="write" + ), + "emails": convert_and_respect_annotation_metadata( + object_=emails, + annotation=typing.Sequence[ScimEmail], + direction="write", + ), + "active": active, + "password": password, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScimUser, + parse_obj_as( + type_=ScimUser, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_user( + self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[ScimUser]: + """ + Get a specific user by ID (requires organization-scoped API key) + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ScimUser] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/scim/Users/{jsonable_encoder(user_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScimUser, + parse_obj_as( + type_=ScimUser, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete_user( + self, user_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[EmptyResponse]: + """ + Remove a user from the organization (requires organization-scoped API key). Note that this only removes the user from the organization but does not delete the user entity itself. + + Parameters + ---------- + user_id : str + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[EmptyResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/scim/Users/{jsonable_encoder(user_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + EmptyResponse, + parse_obj_as( + type_=EmptyResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/scim/types/__init__.py b/langfuse/api/scim/types/__init__.py new file mode 100644 index 000000000..9d6483e3d --- /dev/null +++ b/langfuse/api/scim/types/__init__.py @@ -0,0 +1,92 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .authentication_scheme import AuthenticationScheme + from .bulk_config import BulkConfig + from .empty_response import EmptyResponse + from .filter_config import FilterConfig + from .resource_meta import ResourceMeta + from .resource_type import ResourceType + from .resource_types_response import ResourceTypesResponse + from .schema_extension import SchemaExtension + from .schema_resource import SchemaResource + from .schemas_response import SchemasResponse + from .scim_email import ScimEmail + from .scim_feature_support import ScimFeatureSupport + from .scim_name import ScimName + from .scim_user import ScimUser + from .scim_users_list_response import ScimUsersListResponse + from .service_provider_config import ServiceProviderConfig + from .user_meta import UserMeta +_dynamic_imports: typing.Dict[str, str] = { + "AuthenticationScheme": ".authentication_scheme", + "BulkConfig": ".bulk_config", + "EmptyResponse": ".empty_response", + "FilterConfig": ".filter_config", + "ResourceMeta": ".resource_meta", + "ResourceType": ".resource_type", + "ResourceTypesResponse": ".resource_types_response", + "SchemaExtension": ".schema_extension", + "SchemaResource": ".schema_resource", + "SchemasResponse": ".schemas_response", + "ScimEmail": ".scim_email", + "ScimFeatureSupport": ".scim_feature_support", + "ScimName": ".scim_name", + "ScimUser": ".scim_user", + "ScimUsersListResponse": ".scim_users_list_response", + "ServiceProviderConfig": ".service_provider_config", + "UserMeta": ".user_meta", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "AuthenticationScheme", + "BulkConfig", + "EmptyResponse", + "FilterConfig", + "ResourceMeta", + "ResourceType", + "ResourceTypesResponse", + "SchemaExtension", + "SchemaResource", + "SchemasResponse", + "ScimEmail", + "ScimFeatureSupport", + "ScimName", + "ScimUser", + "ScimUsersListResponse", + "ServiceProviderConfig", + "UserMeta", +] diff --git a/langfuse/api/scim/types/authentication_scheme.py b/langfuse/api/scim/types/authentication_scheme.py new file mode 100644 index 000000000..2128971e8 --- /dev/null +++ b/langfuse/api/scim/types/authentication_scheme.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class AuthenticationScheme(UniversalBaseModel): + name: str + description: str + spec_uri: typing_extensions.Annotated[str, FieldMetadata(alias="specUri")] + type: str + primary: bool + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/bulk_config.py b/langfuse/api/scim/types/bulk_config.py new file mode 100644 index 000000000..099390a33 --- /dev/null +++ b/langfuse/api/scim/types/bulk_config.py @@ -0,0 +1,29 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class BulkConfig(UniversalBaseModel): + supported: bool + max_operations: typing_extensions.Annotated[ + int, FieldMetadata(alias="maxOperations") + ] + max_payload_size: typing_extensions.Annotated[ + int, FieldMetadata(alias="maxPayloadSize") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/empty_response.py b/langfuse/api/scim/types/empty_response.py new file mode 100644 index 000000000..8b1854e9f --- /dev/null +++ b/langfuse/api/scim/types/empty_response.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class EmptyResponse(UniversalBaseModel): + """ + Empty response for 204 No Content responses + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/filter_config.py b/langfuse/api/scim/types/filter_config.py new file mode 100644 index 000000000..7aab95624 --- /dev/null +++ b/langfuse/api/scim/types/filter_config.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class FilterConfig(UniversalBaseModel): + supported: bool + max_results: typing_extensions.Annotated[int, FieldMetadata(alias="maxResults")] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/resource_meta.py b/langfuse/api/scim/types/resource_meta.py new file mode 100644 index 000000000..3db9e3115 --- /dev/null +++ b/langfuse/api/scim/types/resource_meta.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class ResourceMeta(UniversalBaseModel): + resource_type: typing_extensions.Annotated[str, FieldMetadata(alias="resourceType")] + location: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/resource_type.py b/langfuse/api/scim/types/resource_type.py new file mode 100644 index 000000000..3dda09de4 --- /dev/null +++ b/langfuse/api/scim/types/resource_type.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .resource_meta import ResourceMeta +from .schema_extension import SchemaExtension + + +class ResourceType(UniversalBaseModel): + schemas: typing.Optional[typing.List[str]] = None + id: str + name: str + endpoint: str + description: str + schema_: typing_extensions.Annotated[str, FieldMetadata(alias="schema")] + schema_extensions: typing_extensions.Annotated[ + typing.List[SchemaExtension], FieldMetadata(alias="schemaExtensions") + ] + meta: ResourceMeta + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/resource_types_response.py b/langfuse/api/scim/types/resource_types_response.py new file mode 100644 index 000000000..0e5ceae72 --- /dev/null +++ b/langfuse/api/scim/types/resource_types_response.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .resource_type import ResourceType + + +class ResourceTypesResponse(UniversalBaseModel): + schemas: typing.List[str] + total_results: typing_extensions.Annotated[int, FieldMetadata(alias="totalResults")] + resources: typing_extensions.Annotated[ + typing.List[ResourceType], FieldMetadata(alias="Resources") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/schema_extension.py b/langfuse/api/scim/types/schema_extension.py new file mode 100644 index 000000000..4f8d18e85 --- /dev/null +++ b/langfuse/api/scim/types/schema_extension.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class SchemaExtension(UniversalBaseModel): + schema_: typing_extensions.Annotated[str, FieldMetadata(alias="schema")] + required: bool + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/schema_resource.py b/langfuse/api/scim/types/schema_resource.py new file mode 100644 index 000000000..bc667eacb --- /dev/null +++ b/langfuse/api/scim/types/schema_resource.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .resource_meta import ResourceMeta + + +class SchemaResource(UniversalBaseModel): + id: str + name: str + description: str + attributes: typing.List[typing.Any] + meta: ResourceMeta + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/schemas_response.py b/langfuse/api/scim/types/schemas_response.py new file mode 100644 index 000000000..3dc1ca69f --- /dev/null +++ b/langfuse/api/scim/types/schemas_response.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .schema_resource import SchemaResource + + +class SchemasResponse(UniversalBaseModel): + schemas: typing.List[str] + total_results: typing_extensions.Annotated[int, FieldMetadata(alias="totalResults")] + resources: typing_extensions.Annotated[ + typing.List[SchemaResource], FieldMetadata(alias="Resources") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/scim_email.py b/langfuse/api/scim/types/scim_email.py new file mode 100644 index 000000000..b8b0ad893 --- /dev/null +++ b/langfuse/api/scim/types/scim_email.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ScimEmail(UniversalBaseModel): + primary: bool + value: str + type: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/scim_feature_support.py b/langfuse/api/scim/types/scim_feature_support.py new file mode 100644 index 000000000..af0bb997f --- /dev/null +++ b/langfuse/api/scim/types/scim_feature_support.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ScimFeatureSupport(UniversalBaseModel): + supported: bool + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/scim_name.py b/langfuse/api/scim/types/scim_name.py new file mode 100644 index 000000000..14e72d050 --- /dev/null +++ b/langfuse/api/scim/types/scim_name.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ScimName(UniversalBaseModel): + formatted: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/scim_user.py b/langfuse/api/scim/types/scim_user.py new file mode 100644 index 000000000..c65e94f4b --- /dev/null +++ b/langfuse/api/scim/types/scim_user.py @@ -0,0 +1,31 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .scim_email import ScimEmail +from .scim_name import ScimName +from .user_meta import UserMeta + + +class ScimUser(UniversalBaseModel): + schemas: typing.List[str] + id: str + user_name: typing_extensions.Annotated[str, FieldMetadata(alias="userName")] + name: ScimName + emails: typing.List[ScimEmail] + meta: UserMeta + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/scim_users_list_response.py b/langfuse/api/scim/types/scim_users_list_response.py new file mode 100644 index 000000000..17cf2ad3d --- /dev/null +++ b/langfuse/api/scim/types/scim_users_list_response.py @@ -0,0 +1,32 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .scim_user import ScimUser + + +class ScimUsersListResponse(UniversalBaseModel): + schemas: typing.List[str] + total_results: typing_extensions.Annotated[int, FieldMetadata(alias="totalResults")] + start_index: typing_extensions.Annotated[int, FieldMetadata(alias="startIndex")] + items_per_page: typing_extensions.Annotated[ + int, FieldMetadata(alias="itemsPerPage") + ] + resources: typing_extensions.Annotated[ + typing.List[ScimUser], FieldMetadata(alias="Resources") + ] + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/service_provider_config.py b/langfuse/api/scim/types/service_provider_config.py new file mode 100644 index 000000000..bb96fbd3b --- /dev/null +++ b/langfuse/api/scim/types/service_provider_config.py @@ -0,0 +1,43 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .authentication_scheme import AuthenticationScheme +from .bulk_config import BulkConfig +from .filter_config import FilterConfig +from .resource_meta import ResourceMeta +from .scim_feature_support import ScimFeatureSupport + + +class ServiceProviderConfig(UniversalBaseModel): + schemas: typing.List[str] + documentation_uri: typing_extensions.Annotated[ + str, FieldMetadata(alias="documentationUri") + ] + patch: ScimFeatureSupport + bulk: BulkConfig + filter: FilterConfig + change_password: typing_extensions.Annotated[ + ScimFeatureSupport, FieldMetadata(alias="changePassword") + ] + sort: ScimFeatureSupport + etag: ScimFeatureSupport + authentication_schemes: typing_extensions.Annotated[ + typing.List[AuthenticationScheme], FieldMetadata(alias="authenticationSchemes") + ] + meta: ResourceMeta + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/scim/types/user_meta.py b/langfuse/api/scim/types/user_meta.py new file mode 100644 index 000000000..b56933bbb --- /dev/null +++ b/langfuse/api/scim/types/user_meta.py @@ -0,0 +1,27 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class UserMeta(UniversalBaseModel): + resource_type: typing_extensions.Annotated[str, FieldMetadata(alias="resourceType")] + created: typing.Optional[str] = None + last_modified: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="lastModified") + ] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/score/__init__.py b/langfuse/api/score/__init__.py new file mode 100644 index 000000000..3d0c7422a --- /dev/null +++ b/langfuse/api/score/__init__.py @@ -0,0 +1,43 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import CreateScoreRequest, CreateScoreResponse +_dynamic_imports: typing.Dict[str, str] = { + "CreateScoreRequest": ".types", + "CreateScoreResponse": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["CreateScoreRequest", "CreateScoreResponse"] diff --git a/langfuse/api/score/client.py b/langfuse/api/score/client.py new file mode 100644 index 000000000..7a2ba1b83 --- /dev/null +++ b/langfuse/api/score/client.py @@ -0,0 +1,329 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..commons.types.create_score_value import CreateScoreValue +from ..commons.types.score_data_type import ScoreDataType +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawScoreClient, RawScoreClient +from .types.create_score_response import CreateScoreResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class ScoreClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawScoreClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawScoreClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawScoreClient + """ + return self._raw_client + + def create( + self, + *, + name: str, + value: CreateScoreValue, + id: typing.Optional[str] = OMIT, + trace_id: typing.Optional[str] = OMIT, + session_id: typing.Optional[str] = OMIT, + observation_id: typing.Optional[str] = OMIT, + dataset_run_id: typing.Optional[str] = OMIT, + comment: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + environment: typing.Optional[str] = OMIT, + queue_id: typing.Optional[str] = OMIT, + data_type: typing.Optional[ScoreDataType] = OMIT, + config_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> CreateScoreResponse: + """ + Create a score (supports both trace and session scores) + + Parameters + ---------- + name : str + + value : CreateScoreValue + The value of the score. Must be passed as string for categorical scores, and numeric for boolean and numeric scores. Boolean score values must equal either 1 or 0 (true or false) + + id : typing.Optional[str] + + trace_id : typing.Optional[str] + + session_id : typing.Optional[str] + + observation_id : typing.Optional[str] + + dataset_run_id : typing.Optional[str] + + comment : typing.Optional[str] + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + environment : typing.Optional[str] + The environment of the score. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. + + queue_id : typing.Optional[str] + The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. + + data_type : typing.Optional[ScoreDataType] + The data type of the score. When passing a configId this field is inferred. Otherwise, this field must be passed or will default to numeric. + + config_id : typing.Optional[str] + Reference a score config on a score. The unique langfuse identifier of a score config. When passing this field, the dataType and stringValue fields are automatically populated. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CreateScoreResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.score.create( + name="name", + value=1.1, + ) + """ + _response = self._raw_client.create( + name=name, + value=value, + id=id, + trace_id=trace_id, + session_id=session_id, + observation_id=observation_id, + dataset_run_id=dataset_run_id, + comment=comment, + metadata=metadata, + environment=environment, + queue_id=queue_id, + data_type=data_type, + config_id=config_id, + request_options=request_options, + ) + return _response.data + + def delete( + self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Delete a score (supports both trace and session scores) + + Parameters + ---------- + score_id : str + The unique langfuse identifier of a score + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.score.delete( + score_id="scoreId", + ) + """ + _response = self._raw_client.delete(score_id, request_options=request_options) + return _response.data + + +class AsyncScoreClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawScoreClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawScoreClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawScoreClient + """ + return self._raw_client + + async def create( + self, + *, + name: str, + value: CreateScoreValue, + id: typing.Optional[str] = OMIT, + trace_id: typing.Optional[str] = OMIT, + session_id: typing.Optional[str] = OMIT, + observation_id: typing.Optional[str] = OMIT, + dataset_run_id: typing.Optional[str] = OMIT, + comment: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + environment: typing.Optional[str] = OMIT, + queue_id: typing.Optional[str] = OMIT, + data_type: typing.Optional[ScoreDataType] = OMIT, + config_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> CreateScoreResponse: + """ + Create a score (supports both trace and session scores) + + Parameters + ---------- + name : str + + value : CreateScoreValue + The value of the score. Must be passed as string for categorical scores, and numeric for boolean and numeric scores. Boolean score values must equal either 1 or 0 (true or false) + + id : typing.Optional[str] + + trace_id : typing.Optional[str] + + session_id : typing.Optional[str] + + observation_id : typing.Optional[str] + + dataset_run_id : typing.Optional[str] + + comment : typing.Optional[str] + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + environment : typing.Optional[str] + The environment of the score. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. + + queue_id : typing.Optional[str] + The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. + + data_type : typing.Optional[ScoreDataType] + The data type of the score. When passing a configId this field is inferred. Otherwise, this field must be passed or will default to numeric. + + config_id : typing.Optional[str] + Reference a score config on a score. The unique langfuse identifier of a score config. When passing this field, the dataType and stringValue fields are automatically populated. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + CreateScoreResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.score.create( + name="name", + value=1.1, + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create( + name=name, + value=value, + id=id, + trace_id=trace_id, + session_id=session_id, + observation_id=observation_id, + dataset_run_id=dataset_run_id, + comment=comment, + metadata=metadata, + environment=environment, + queue_id=queue_id, + data_type=data_type, + config_id=config_id, + request_options=request_options, + ) + return _response.data + + async def delete( + self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> None: + """ + Delete a score (supports both trace and session scores) + + Parameters + ---------- + score_id : str + The unique langfuse identifier of a score + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + None + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.score.delete( + score_id="scoreId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.delete( + score_id, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/score/raw_client.py b/langfuse/api/score/raw_client.py new file mode 100644 index 000000000..7c20eee08 --- /dev/null +++ b/langfuse/api/score/raw_client.py @@ -0,0 +1,545 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..commons.types.create_score_value import CreateScoreValue +from ..commons.types.score_data_type import ScoreDataType +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from ..core.serialization import convert_and_respect_annotation_metadata +from .types.create_score_response import CreateScoreResponse + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawScoreClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def create( + self, + *, + name: str, + value: CreateScoreValue, + id: typing.Optional[str] = OMIT, + trace_id: typing.Optional[str] = OMIT, + session_id: typing.Optional[str] = OMIT, + observation_id: typing.Optional[str] = OMIT, + dataset_run_id: typing.Optional[str] = OMIT, + comment: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + environment: typing.Optional[str] = OMIT, + queue_id: typing.Optional[str] = OMIT, + data_type: typing.Optional[ScoreDataType] = OMIT, + config_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[CreateScoreResponse]: + """ + Create a score (supports both trace and session scores) + + Parameters + ---------- + name : str + + value : CreateScoreValue + The value of the score. Must be passed as string for categorical scores, and numeric for boolean and numeric scores. Boolean score values must equal either 1 or 0 (true or false) + + id : typing.Optional[str] + + trace_id : typing.Optional[str] + + session_id : typing.Optional[str] + + observation_id : typing.Optional[str] + + dataset_run_id : typing.Optional[str] + + comment : typing.Optional[str] + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + environment : typing.Optional[str] + The environment of the score. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. + + queue_id : typing.Optional[str] + The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. + + data_type : typing.Optional[ScoreDataType] + The data type of the score. When passing a configId this field is inferred. Otherwise, this field must be passed or will default to numeric. + + config_id : typing.Optional[str] + Reference a score config on a score. The unique langfuse identifier of a score config. When passing this field, the dataType and stringValue fields are automatically populated. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[CreateScoreResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/scores", + method="POST", + json={ + "id": id, + "traceId": trace_id, + "sessionId": session_id, + "observationId": observation_id, + "datasetRunId": dataset_run_id, + "name": name, + "value": convert_and_respect_annotation_metadata( + object_=value, annotation=CreateScoreValue, direction="write" + ), + "comment": comment, + "metadata": metadata, + "environment": environment, + "queueId": queue_id, + "dataType": data_type, + "configId": config_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CreateScoreResponse, + parse_obj_as( + type_=CreateScoreResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete( + self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[None]: + """ + Delete a score (supports both trace and session scores) + + Parameters + ---------- + score_id : str + The unique langfuse identifier of a score + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[None] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/scores/{jsonable_encoder(score_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return HttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawScoreClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def create( + self, + *, + name: str, + value: CreateScoreValue, + id: typing.Optional[str] = OMIT, + trace_id: typing.Optional[str] = OMIT, + session_id: typing.Optional[str] = OMIT, + observation_id: typing.Optional[str] = OMIT, + dataset_run_id: typing.Optional[str] = OMIT, + comment: typing.Optional[str] = OMIT, + metadata: typing.Optional[typing.Dict[str, typing.Any]] = OMIT, + environment: typing.Optional[str] = OMIT, + queue_id: typing.Optional[str] = OMIT, + data_type: typing.Optional[ScoreDataType] = OMIT, + config_id: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[CreateScoreResponse]: + """ + Create a score (supports both trace and session scores) + + Parameters + ---------- + name : str + + value : CreateScoreValue + The value of the score. Must be passed as string for categorical scores, and numeric for boolean and numeric scores. Boolean score values must equal either 1 or 0 (true or false) + + id : typing.Optional[str] + + trace_id : typing.Optional[str] + + session_id : typing.Optional[str] + + observation_id : typing.Optional[str] + + dataset_run_id : typing.Optional[str] + + comment : typing.Optional[str] + + metadata : typing.Optional[typing.Dict[str, typing.Any]] + + environment : typing.Optional[str] + The environment of the score. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. + + queue_id : typing.Optional[str] + The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. + + data_type : typing.Optional[ScoreDataType] + The data type of the score. When passing a configId this field is inferred. Otherwise, this field must be passed or will default to numeric. + + config_id : typing.Optional[str] + Reference a score config on a score. The unique langfuse identifier of a score config. When passing this field, the dataType and stringValue fields are automatically populated. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[CreateScoreResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/scores", + method="POST", + json={ + "id": id, + "traceId": trace_id, + "sessionId": session_id, + "observationId": observation_id, + "datasetRunId": dataset_run_id, + "name": name, + "value": convert_and_respect_annotation_metadata( + object_=value, annotation=CreateScoreValue, direction="write" + ), + "comment": comment, + "metadata": metadata, + "environment": environment, + "queueId": queue_id, + "dataType": data_type, + "configId": config_id, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + CreateScoreResponse, + parse_obj_as( + type_=CreateScoreResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete( + self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[None]: + """ + Delete a score (supports both trace and session scores) + + Parameters + ---------- + score_id : str + The unique langfuse identifier of a score + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[None] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/scores/{jsonable_encoder(score_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + return AsyncHttpResponse(response=_response, data=None) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/score/types/__init__.py b/langfuse/api/score/types/__init__.py new file mode 100644 index 000000000..4a759a978 --- /dev/null +++ b/langfuse/api/score/types/__init__.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .create_score_request import CreateScoreRequest + from .create_score_response import CreateScoreResponse +_dynamic_imports: typing.Dict[str, str] = { + "CreateScoreRequest": ".create_score_request", + "CreateScoreResponse": ".create_score_response", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["CreateScoreRequest", "CreateScoreResponse"] diff --git a/langfuse/api/score/types/create_score_request.py b/langfuse/api/score/types/create_score_request.py new file mode 100644 index 000000000..8c24c19a5 --- /dev/null +++ b/langfuse/api/score/types/create_score_request.py @@ -0,0 +1,82 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...commons.types.create_score_value import CreateScoreValue +from ...commons.types.score_data_type import ScoreDataType +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class CreateScoreRequest(UniversalBaseModel): + """ + Examples + -------- + from langfuse.score import CreateScoreRequest + + CreateScoreRequest( + name="novelty", + value=0.9, + trace_id="cdef-1234-5678-90ab", + ) + """ + + id: typing.Optional[str] = None + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = None + session_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sessionId") + ] = None + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + dataset_run_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="datasetRunId") + ] = None + name: str + value: CreateScoreValue = pydantic.Field() + """ + The value of the score. Must be passed as string for categorical scores, and numeric for boolean and numeric scores. Boolean score values must equal either 1 or 0 (true or false) + """ + + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Dict[str, typing.Any]] = None + environment: typing.Optional[str] = pydantic.Field(default=None) + """ + The environment of the score. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. + """ + + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = pydantic.Field(default=None) + """ + The annotation queue referenced by the score. Indicates if score was initially created while processing annotation queue. + """ + + data_type: typing_extensions.Annotated[ + typing.Optional[ScoreDataType], FieldMetadata(alias="dataType") + ] = pydantic.Field(default=None) + """ + The data type of the score. When passing a configId this field is inferred. Otherwise, this field must be passed or will default to numeric. + """ + + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = pydantic.Field(default=None) + """ + Reference a score config on a score. The unique langfuse identifier of a score config. When passing this field, the dataType and stringValue fields are automatically populated. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/score/types/create_score_response.py b/langfuse/api/score/types/create_score_response.py new file mode 100644 index 000000000..b0c6cdbbf --- /dev/null +++ b/langfuse/api/score/types/create_score_response.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class CreateScoreResponse(UniversalBaseModel): + id: str = pydantic.Field() + """ + The id of the created object in Langfuse + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/score_configs/__init__.py b/langfuse/api/score_configs/__init__.py new file mode 100644 index 000000000..16f409522 --- /dev/null +++ b/langfuse/api/score_configs/__init__.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import CreateScoreConfigRequest, ScoreConfigs, UpdateScoreConfigRequest +_dynamic_imports: typing.Dict[str, str] = { + "CreateScoreConfigRequest": ".types", + "ScoreConfigs": ".types", + "UpdateScoreConfigRequest": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["CreateScoreConfigRequest", "ScoreConfigs", "UpdateScoreConfigRequest"] diff --git a/langfuse/api/score_configs/client.py b/langfuse/api/score_configs/client.py new file mode 100644 index 000000000..1b5f93bb0 --- /dev/null +++ b/langfuse/api/score_configs/client.py @@ -0,0 +1,524 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..commons.types.config_category import ConfigCategory +from ..commons.types.score_config import ScoreConfig +from ..commons.types.score_data_type import ScoreDataType +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawScoreConfigsClient, RawScoreConfigsClient +from .types.score_configs import ScoreConfigs + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class ScoreConfigsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawScoreConfigsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawScoreConfigsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawScoreConfigsClient + """ + return self._raw_client + + def create( + self, + *, + name: str, + data_type: ScoreDataType, + categories: typing.Optional[typing.Sequence[ConfigCategory]] = OMIT, + min_value: typing.Optional[float] = OMIT, + max_value: typing.Optional[float] = OMIT, + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> ScoreConfig: + """ + Create a score configuration (config). Score configs are used to define the structure of scores + + Parameters + ---------- + name : str + + data_type : ScoreDataType + + categories : typing.Optional[typing.Sequence[ConfigCategory]] + Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed + + min_value : typing.Optional[float] + Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ + + max_value : typing.Optional[float] + Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ + + description : typing.Optional[str] + Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScoreConfig + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.score_configs.create( + name="name", + data_type="NUMERIC", + ) + """ + _response = self._raw_client.create( + name=name, + data_type=data_type, + categories=categories, + min_value=min_value, + max_value=max_value, + description=description, + request_options=request_options, + ) + return _response.data + + def get( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ScoreConfigs: + """ + Get all score configs + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScoreConfigs + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.score_configs.get() + """ + _response = self._raw_client.get( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + def get_by_id( + self, config_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> ScoreConfig: + """ + Get a score config + + Parameters + ---------- + config_id : str + The unique langfuse identifier of a score config + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScoreConfig + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.score_configs.get_by_id( + config_id="configId", + ) + """ + _response = self._raw_client.get_by_id( + config_id, request_options=request_options + ) + return _response.data + + def update( + self, + config_id: str, + *, + is_archived: typing.Optional[bool] = OMIT, + name: typing.Optional[str] = OMIT, + categories: typing.Optional[typing.Sequence[ConfigCategory]] = OMIT, + min_value: typing.Optional[float] = OMIT, + max_value: typing.Optional[float] = OMIT, + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> ScoreConfig: + """ + Update a score config + + Parameters + ---------- + config_id : str + The unique langfuse identifier of a score config + + is_archived : typing.Optional[bool] + The status of the score config showing if it is archived or not + + name : typing.Optional[str] + The name of the score config + + categories : typing.Optional[typing.Sequence[ConfigCategory]] + Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed + + min_value : typing.Optional[float] + Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ + + max_value : typing.Optional[float] + Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ + + description : typing.Optional[str] + Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScoreConfig + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.score_configs.update( + config_id="configId", + ) + """ + _response = self._raw_client.update( + config_id, + is_archived=is_archived, + name=name, + categories=categories, + min_value=min_value, + max_value=max_value, + description=description, + request_options=request_options, + ) + return _response.data + + +class AsyncScoreConfigsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawScoreConfigsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawScoreConfigsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawScoreConfigsClient + """ + return self._raw_client + + async def create( + self, + *, + name: str, + data_type: ScoreDataType, + categories: typing.Optional[typing.Sequence[ConfigCategory]] = OMIT, + min_value: typing.Optional[float] = OMIT, + max_value: typing.Optional[float] = OMIT, + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> ScoreConfig: + """ + Create a score configuration (config). Score configs are used to define the structure of scores + + Parameters + ---------- + name : str + + data_type : ScoreDataType + + categories : typing.Optional[typing.Sequence[ConfigCategory]] + Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed + + min_value : typing.Optional[float] + Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ + + max_value : typing.Optional[float] + Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ + + description : typing.Optional[str] + Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScoreConfig + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.score_configs.create( + name="name", + data_type="NUMERIC", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.create( + name=name, + data_type=data_type, + categories=categories, + min_value=min_value, + max_value=max_value, + description=description, + request_options=request_options, + ) + return _response.data + + async def get( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ScoreConfigs: + """ + Get all score configs + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScoreConfigs + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.score_configs.get() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get( + page=page, limit=limit, request_options=request_options + ) + return _response.data + + async def get_by_id( + self, config_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> ScoreConfig: + """ + Get a score config + + Parameters + ---------- + config_id : str + The unique langfuse identifier of a score config + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScoreConfig + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.score_configs.get_by_id( + config_id="configId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_by_id( + config_id, request_options=request_options + ) + return _response.data + + async def update( + self, + config_id: str, + *, + is_archived: typing.Optional[bool] = OMIT, + name: typing.Optional[str] = OMIT, + categories: typing.Optional[typing.Sequence[ConfigCategory]] = OMIT, + min_value: typing.Optional[float] = OMIT, + max_value: typing.Optional[float] = OMIT, + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> ScoreConfig: + """ + Update a score config + + Parameters + ---------- + config_id : str + The unique langfuse identifier of a score config + + is_archived : typing.Optional[bool] + The status of the score config showing if it is archived or not + + name : typing.Optional[str] + The name of the score config + + categories : typing.Optional[typing.Sequence[ConfigCategory]] + Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed + + min_value : typing.Optional[float] + Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ + + max_value : typing.Optional[float] + Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ + + description : typing.Optional[str] + Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ScoreConfig + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.score_configs.update( + config_id="configId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.update( + config_id, + is_archived=is_archived, + name=name, + categories=categories, + min_value=min_value, + max_value=max_value, + description=description, + request_options=request_options, + ) + return _response.data diff --git a/langfuse/api/score_configs/raw_client.py b/langfuse/api/score_configs/raw_client.py new file mode 100644 index 000000000..733f79214 --- /dev/null +++ b/langfuse/api/score_configs/raw_client.py @@ -0,0 +1,1012 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..commons.types.config_category import ConfigCategory +from ..commons.types.score_config import ScoreConfig +from ..commons.types.score_data_type import ScoreDataType +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from ..core.serialization import convert_and_respect_annotation_metadata +from .types.score_configs import ScoreConfigs + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawScoreConfigsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def create( + self, + *, + name: str, + data_type: ScoreDataType, + categories: typing.Optional[typing.Sequence[ConfigCategory]] = OMIT, + min_value: typing.Optional[float] = OMIT, + max_value: typing.Optional[float] = OMIT, + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ScoreConfig]: + """ + Create a score configuration (config). Score configs are used to define the structure of scores + + Parameters + ---------- + name : str + + data_type : ScoreDataType + + categories : typing.Optional[typing.Sequence[ConfigCategory]] + Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed + + min_value : typing.Optional[float] + Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ + + max_value : typing.Optional[float] + Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ + + description : typing.Optional[str] + Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ScoreConfig] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/score-configs", + method="POST", + json={ + "name": name, + "dataType": data_type, + "categories": convert_and_respect_annotation_metadata( + object_=categories, + annotation=typing.Sequence[ConfigCategory], + direction="write", + ), + "minValue": min_value, + "maxValue": max_value, + "description": description, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScoreConfig, + parse_obj_as( + type_=ScoreConfig, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ScoreConfigs]: + """ + Get all score configs + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ScoreConfigs] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/score-configs", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScoreConfigs, + parse_obj_as( + type_=ScoreConfigs, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get_by_id( + self, config_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[ScoreConfig]: + """ + Get a score config + + Parameters + ---------- + config_id : str + The unique langfuse identifier of a score config + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ScoreConfig] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/score-configs/{jsonable_encoder(config_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScoreConfig, + parse_obj_as( + type_=ScoreConfig, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def update( + self, + config_id: str, + *, + is_archived: typing.Optional[bool] = OMIT, + name: typing.Optional[str] = OMIT, + categories: typing.Optional[typing.Sequence[ConfigCategory]] = OMIT, + min_value: typing.Optional[float] = OMIT, + max_value: typing.Optional[float] = OMIT, + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ScoreConfig]: + """ + Update a score config + + Parameters + ---------- + config_id : str + The unique langfuse identifier of a score config + + is_archived : typing.Optional[bool] + The status of the score config showing if it is archived or not + + name : typing.Optional[str] + The name of the score config + + categories : typing.Optional[typing.Sequence[ConfigCategory]] + Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed + + min_value : typing.Optional[float] + Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ + + max_value : typing.Optional[float] + Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ + + description : typing.Optional[str] + Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ScoreConfig] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/score-configs/{jsonable_encoder(config_id)}", + method="PATCH", + json={ + "isArchived": is_archived, + "name": name, + "categories": convert_and_respect_annotation_metadata( + object_=categories, + annotation=typing.Sequence[ConfigCategory], + direction="write", + ), + "minValue": min_value, + "maxValue": max_value, + "description": description, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScoreConfig, + parse_obj_as( + type_=ScoreConfig, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawScoreConfigsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def create( + self, + *, + name: str, + data_type: ScoreDataType, + categories: typing.Optional[typing.Sequence[ConfigCategory]] = OMIT, + min_value: typing.Optional[float] = OMIT, + max_value: typing.Optional[float] = OMIT, + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ScoreConfig]: + """ + Create a score configuration (config). Score configs are used to define the structure of scores + + Parameters + ---------- + name : str + + data_type : ScoreDataType + + categories : typing.Optional[typing.Sequence[ConfigCategory]] + Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed + + min_value : typing.Optional[float] + Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ + + max_value : typing.Optional[float] + Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ + + description : typing.Optional[str] + Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ScoreConfig] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/score-configs", + method="POST", + json={ + "name": name, + "dataType": data_type, + "categories": convert_and_respect_annotation_metadata( + object_=categories, + annotation=typing.Sequence[ConfigCategory], + direction="write", + ), + "minValue": min_value, + "maxValue": max_value, + "description": description, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScoreConfig, + parse_obj_as( + type_=ScoreConfig, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ScoreConfigs]: + """ + Get all score configs + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ScoreConfigs] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/score-configs", + method="GET", + params={ + "page": page, + "limit": limit, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScoreConfigs, + parse_obj_as( + type_=ScoreConfigs, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get_by_id( + self, config_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[ScoreConfig]: + """ + Get a score config + + Parameters + ---------- + config_id : str + The unique langfuse identifier of a score config + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ScoreConfig] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/score-configs/{jsonable_encoder(config_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScoreConfig, + parse_obj_as( + type_=ScoreConfig, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def update( + self, + config_id: str, + *, + is_archived: typing.Optional[bool] = OMIT, + name: typing.Optional[str] = OMIT, + categories: typing.Optional[typing.Sequence[ConfigCategory]] = OMIT, + min_value: typing.Optional[float] = OMIT, + max_value: typing.Optional[float] = OMIT, + description: typing.Optional[str] = OMIT, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ScoreConfig]: + """ + Update a score config + + Parameters + ---------- + config_id : str + The unique langfuse identifier of a score config + + is_archived : typing.Optional[bool] + The status of the score config showing if it is archived or not + + name : typing.Optional[str] + The name of the score config + + categories : typing.Optional[typing.Sequence[ConfigCategory]] + Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed + + min_value : typing.Optional[float] + Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ + + max_value : typing.Optional[float] + Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ + + description : typing.Optional[str] + Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ScoreConfig] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/score-configs/{jsonable_encoder(config_id)}", + method="PATCH", + json={ + "isArchived": is_archived, + "name": name, + "categories": convert_and_respect_annotation_metadata( + object_=categories, + annotation=typing.Sequence[ConfigCategory], + direction="write", + ), + "minValue": min_value, + "maxValue": max_value, + "description": description, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ScoreConfig, + parse_obj_as( + type_=ScoreConfig, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/score_configs/types/__init__.py b/langfuse/api/score_configs/types/__init__.py new file mode 100644 index 000000000..10ef4f679 --- /dev/null +++ b/langfuse/api/score_configs/types/__init__.py @@ -0,0 +1,46 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .create_score_config_request import CreateScoreConfigRequest + from .score_configs import ScoreConfigs + from .update_score_config_request import UpdateScoreConfigRequest +_dynamic_imports: typing.Dict[str, str] = { + "CreateScoreConfigRequest": ".create_score_config_request", + "ScoreConfigs": ".score_configs", + "UpdateScoreConfigRequest": ".update_score_config_request", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["CreateScoreConfigRequest", "ScoreConfigs", "UpdateScoreConfigRequest"] diff --git a/langfuse/api/score_configs/types/create_score_config_request.py b/langfuse/api/score_configs/types/create_score_config_request.py new file mode 100644 index 000000000..87b13a054 --- /dev/null +++ b/langfuse/api/score_configs/types/create_score_config_request.py @@ -0,0 +1,53 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...commons.types.config_category import ConfigCategory +from ...commons.types.score_data_type import ScoreDataType +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class CreateScoreConfigRequest(UniversalBaseModel): + name: str + data_type: typing_extensions.Annotated[ + ScoreDataType, FieldMetadata(alias="dataType") + ] + categories: typing.Optional[typing.List[ConfigCategory]] = pydantic.Field( + default=None + ) + """ + Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed + """ + + min_value: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="minValue") + ] = pydantic.Field(default=None) + """ + Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ + """ + + max_value: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="maxValue") + ] = pydantic.Field(default=None) + """ + Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ + """ + + description: typing.Optional[str] = pydantic.Field(default=None) + """ + Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/score_configs/types/score_configs.py b/langfuse/api/score_configs/types/score_configs.py new file mode 100644 index 000000000..9fe613571 --- /dev/null +++ b/langfuse/api/score_configs/types/score_configs.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.score_config import ScoreConfig +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse + + +class ScoreConfigs(UniversalBaseModel): + data: typing.List[ScoreConfig] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/score_configs/types/update_score_config_request.py b/langfuse/api/score_configs/types/update_score_config_request.py new file mode 100644 index 000000000..553347baf --- /dev/null +++ b/langfuse/api/score_configs/types/update_score_config_request.py @@ -0,0 +1,60 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...commons.types.config_category import ConfigCategory +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class UpdateScoreConfigRequest(UniversalBaseModel): + is_archived: typing_extensions.Annotated[ + typing.Optional[bool], FieldMetadata(alias="isArchived") + ] = pydantic.Field(default=None) + """ + The status of the score config showing if it is archived or not + """ + + name: typing.Optional[str] = pydantic.Field(default=None) + """ + The name of the score config + """ + + categories: typing.Optional[typing.List[ConfigCategory]] = pydantic.Field( + default=None + ) + """ + Configure custom categories for categorical scores. Pass a list of objects with `label` and `value` properties. Categories are autogenerated for boolean configs and cannot be passed + """ + + min_value: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="minValue") + ] = pydantic.Field(default=None) + """ + Configure a minimum value for numerical scores. If not set, the minimum value defaults to -∞ + """ + + max_value: typing_extensions.Annotated[ + typing.Optional[float], FieldMetadata(alias="maxValue") + ] = pydantic.Field(default=None) + """ + Configure a maximum value for numerical scores. If not set, the maximum value defaults to +∞ + """ + + description: typing.Optional[str] = pydantic.Field(default=None) + """ + Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/score_v2/__init__.py b/langfuse/api/score_v2/__init__.py new file mode 100644 index 000000000..2d0fcec36 --- /dev/null +++ b/langfuse/api/score_v2/__init__.py @@ -0,0 +1,70 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ( + GetScoresResponse, + GetScoresResponseData, + GetScoresResponseDataBoolean, + GetScoresResponseDataCategorical, + GetScoresResponseDataNumeric, + GetScoresResponseData_Boolean, + GetScoresResponseData_Categorical, + GetScoresResponseData_Numeric, + GetScoresResponseTraceData, + ) +_dynamic_imports: typing.Dict[str, str] = { + "GetScoresResponse": ".types", + "GetScoresResponseData": ".types", + "GetScoresResponseDataBoolean": ".types", + "GetScoresResponseDataCategorical": ".types", + "GetScoresResponseDataNumeric": ".types", + "GetScoresResponseData_Boolean": ".types", + "GetScoresResponseData_Categorical": ".types", + "GetScoresResponseData_Numeric": ".types", + "GetScoresResponseTraceData": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "GetScoresResponse", + "GetScoresResponseData", + "GetScoresResponseDataBoolean", + "GetScoresResponseDataCategorical", + "GetScoresResponseDataNumeric", + "GetScoresResponseData_Boolean", + "GetScoresResponseData_Categorical", + "GetScoresResponseData_Numeric", + "GetScoresResponseTraceData", +] diff --git a/langfuse/api/score_v2/client.py b/langfuse/api/score_v2/client.py new file mode 100644 index 000000000..a4eefb828 --- /dev/null +++ b/langfuse/api/score_v2/client.py @@ -0,0 +1,390 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ..commons.types.score import Score +from ..commons.types.score_data_type import ScoreDataType +from ..commons.types.score_source import ScoreSource +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawScoreV2Client, RawScoreV2Client +from .types.get_scores_response import GetScoresResponse + + +class ScoreV2Client: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawScoreV2Client(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawScoreV2Client: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawScoreV2Client + """ + return self._raw_client + + def get( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + user_id: typing.Optional[str] = None, + name: typing.Optional[str] = None, + from_timestamp: typing.Optional[dt.datetime] = None, + to_timestamp: typing.Optional[dt.datetime] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + source: typing.Optional[ScoreSource] = None, + operator: typing.Optional[str] = None, + value: typing.Optional[float] = None, + score_ids: typing.Optional[str] = None, + config_id: typing.Optional[str] = None, + session_id: typing.Optional[str] = None, + dataset_run_id: typing.Optional[str] = None, + trace_id: typing.Optional[str] = None, + queue_id: typing.Optional[str] = None, + data_type: typing.Optional[ScoreDataType] = None, + trace_tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> GetScoresResponse: + """ + Get a list of scores (supports both trace and session scores) + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. + + user_id : typing.Optional[str] + Retrieve only scores with this userId associated to the trace. + + name : typing.Optional[str] + Retrieve only scores with this name. + + from_timestamp : typing.Optional[dt.datetime] + Optional filter to only include scores created on or after a certain datetime (ISO 8601) + + to_timestamp : typing.Optional[dt.datetime] + Optional filter to only include scores created before a certain datetime (ISO 8601) + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for scores where the environment is one of the provided values. + + source : typing.Optional[ScoreSource] + Retrieve only scores from a specific source. + + operator : typing.Optional[str] + Retrieve only scores with value. + + value : typing.Optional[float] + Retrieve only scores with value. + + score_ids : typing.Optional[str] + Comma-separated list of score IDs to limit the results to. + + config_id : typing.Optional[str] + Retrieve only scores with a specific configId. + + session_id : typing.Optional[str] + Retrieve only scores with a specific sessionId. + + dataset_run_id : typing.Optional[str] + Retrieve only scores with a specific datasetRunId. + + trace_id : typing.Optional[str] + Retrieve only scores with a specific traceId. + + queue_id : typing.Optional[str] + Retrieve only scores with a specific annotation queueId. + + data_type : typing.Optional[ScoreDataType] + Retrieve only scores with a specific dataType. + + trace_tags : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Only scores linked to traces that include all of these tags will be returned. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetScoresResponse + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.score_v2.get() + """ + _response = self._raw_client.get( + page=page, + limit=limit, + user_id=user_id, + name=name, + from_timestamp=from_timestamp, + to_timestamp=to_timestamp, + environment=environment, + source=source, + operator=operator, + value=value, + score_ids=score_ids, + config_id=config_id, + session_id=session_id, + dataset_run_id=dataset_run_id, + trace_id=trace_id, + queue_id=queue_id, + data_type=data_type, + trace_tags=trace_tags, + request_options=request_options, + ) + return _response.data + + def get_by_id( + self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> Score: + """ + Get a score (supports both trace and session scores) + + Parameters + ---------- + score_id : str + The unique langfuse identifier of a score + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Score + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.score_v2.get_by_id( + score_id="scoreId", + ) + """ + _response = self._raw_client.get_by_id( + score_id, request_options=request_options + ) + return _response.data + + +class AsyncScoreV2Client: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawScoreV2Client(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawScoreV2Client: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawScoreV2Client + """ + return self._raw_client + + async def get( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + user_id: typing.Optional[str] = None, + name: typing.Optional[str] = None, + from_timestamp: typing.Optional[dt.datetime] = None, + to_timestamp: typing.Optional[dt.datetime] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + source: typing.Optional[ScoreSource] = None, + operator: typing.Optional[str] = None, + value: typing.Optional[float] = None, + score_ids: typing.Optional[str] = None, + config_id: typing.Optional[str] = None, + session_id: typing.Optional[str] = None, + dataset_run_id: typing.Optional[str] = None, + trace_id: typing.Optional[str] = None, + queue_id: typing.Optional[str] = None, + data_type: typing.Optional[ScoreDataType] = None, + trace_tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> GetScoresResponse: + """ + Get a list of scores (supports both trace and session scores) + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1. + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. + + user_id : typing.Optional[str] + Retrieve only scores with this userId associated to the trace. + + name : typing.Optional[str] + Retrieve only scores with this name. + + from_timestamp : typing.Optional[dt.datetime] + Optional filter to only include scores created on or after a certain datetime (ISO 8601) + + to_timestamp : typing.Optional[dt.datetime] + Optional filter to only include scores created before a certain datetime (ISO 8601) + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for scores where the environment is one of the provided values. + + source : typing.Optional[ScoreSource] + Retrieve only scores from a specific source. + + operator : typing.Optional[str] + Retrieve only scores with value. + + value : typing.Optional[float] + Retrieve only scores with value. + + score_ids : typing.Optional[str] + Comma-separated list of score IDs to limit the results to. + + config_id : typing.Optional[str] + Retrieve only scores with a specific configId. + + session_id : typing.Optional[str] + Retrieve only scores with a specific sessionId. + + dataset_run_id : typing.Optional[str] + Retrieve only scores with a specific datasetRunId. + + trace_id : typing.Optional[str] + Retrieve only scores with a specific traceId. + + queue_id : typing.Optional[str] + Retrieve only scores with a specific annotation queueId. + + data_type : typing.Optional[ScoreDataType] + Retrieve only scores with a specific dataType. + + trace_tags : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Only scores linked to traces that include all of these tags will be returned. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + GetScoresResponse + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.score_v2.get() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get( + page=page, + limit=limit, + user_id=user_id, + name=name, + from_timestamp=from_timestamp, + to_timestamp=to_timestamp, + environment=environment, + source=source, + operator=operator, + value=value, + score_ids=score_ids, + config_id=config_id, + session_id=session_id, + dataset_run_id=dataset_run_id, + trace_id=trace_id, + queue_id=queue_id, + data_type=data_type, + trace_tags=trace_tags, + request_options=request_options, + ) + return _response.data + + async def get_by_id( + self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> Score: + """ + Get a score (supports both trace and session scores) + + Parameters + ---------- + score_id : str + The unique langfuse identifier of a score + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + Score + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.score_v2.get_by_id( + score_id="scoreId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_by_id( + score_id, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/resources/score_v_2/client.py b/langfuse/api/score_v2/raw_client.py similarity index 56% rename from langfuse/api/resources/score_v_2/client.py rename to langfuse/api/score_v2/raw_client.py index 04569dc3a..0fb0b1836 100644 --- a/langfuse/api/resources/score_v_2/client.py +++ b/langfuse/api/score_v2/raw_client.py @@ -4,12 +4,6 @@ import typing from json.decoder import JSONDecodeError -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.datetime_utils import serialize_datetime -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions from ..commons.errors.access_denied_error import AccessDeniedError from ..commons.errors.error import Error from ..commons.errors.method_not_allowed_error import MethodNotAllowedError @@ -18,10 +12,17 @@ from ..commons.types.score import Score from ..commons.types.score_data_type import ScoreDataType from ..commons.types.score_source import ScoreSource +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.datetime_utils import serialize_datetime +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions from .types.get_scores_response import GetScoresResponse -class ScoreV2Client: +class RawScoreV2Client: def __init__(self, *, client_wrapper: SyncClientWrapper): self._client_wrapper = client_wrapper @@ -47,7 +48,7 @@ def get( data_type: typing.Optional[ScoreDataType] = None, trace_tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> GetScoresResponse: + ) -> HttpResponse[GetScoresResponse]: """ Get a list of scores (supports both trace and session scores) @@ -112,21 +113,7 @@ def get( Returns ------- - GetScoresResponse - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.score_v_2.get() + HttpResponse[GetScoresResponse] """ _response = self._client_wrapper.httpx_client.request( "api/public/v2/scores", @@ -159,33 +146,85 @@ def get( ) try: if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(GetScoresResponse, _response.json()) # type: ignore + _data = typing.cast( + GetScoresResponse, + parse_obj_as( + type_=GetScoresResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 401: raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 405: raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 404: raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) _response_json = _response.json() except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) def get_by_id( self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> Score: + ) -> HttpResponse[Score]: """ Get a score (supports both trace and session scores) @@ -199,23 +238,7 @@ def get_by_id( Returns ------- - Score - - Examples - -------- - from langfuse.client import FernLangfuse - - client = FernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - client.score_v_2.get_by_id( - score_id="scoreId", - ) + HttpResponse[Score] """ _response = self._client_wrapper.httpx_client.request( f"api/public/v2/scores/{jsonable_encoder(score_id)}", @@ -224,32 +247,84 @@ def get_by_id( ) try: if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Score, _response.json()) # type: ignore + _data = typing.cast( + Score, + parse_obj_as( + type_=Score, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 401: raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 405: raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 404: raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) _response_json = _response.json() except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) -class AsyncScoreV2Client: +class AsyncRawScoreV2Client: def __init__(self, *, client_wrapper: AsyncClientWrapper): self._client_wrapper = client_wrapper @@ -275,7 +350,7 @@ async def get( data_type: typing.Optional[ScoreDataType] = None, trace_tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, request_options: typing.Optional[RequestOptions] = None, - ) -> GetScoresResponse: + ) -> AsyncHttpResponse[GetScoresResponse]: """ Get a list of scores (supports both trace and session scores) @@ -340,29 +415,7 @@ async def get( Returns ------- - GetScoresResponse - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.score_v_2.get() - - - asyncio.run(main()) + AsyncHttpResponse[GetScoresResponse] """ _response = await self._client_wrapper.httpx_client.request( "api/public/v2/scores", @@ -395,33 +448,85 @@ async def main() -> None: ) try: if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(GetScoresResponse, _response.json()) # type: ignore + _data = typing.cast( + GetScoresResponse, + parse_obj_as( + type_=GetScoresResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 401: raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 405: raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 404: raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) _response_json = _response.json() except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) async def get_by_id( self, score_id: str, *, request_options: typing.Optional[RequestOptions] = None - ) -> Score: + ) -> AsyncHttpResponse[Score]: """ Get a score (supports both trace and session scores) @@ -435,31 +540,7 @@ async def get_by_id( Returns ------- - Score - - Examples - -------- - import asyncio - - from langfuse.client import AsyncFernLangfuse - - client = AsyncFernLangfuse( - x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", - x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", - x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", - username="YOUR_USERNAME", - password="YOUR_PASSWORD", - base_url="https://yourhost.com/path/to/api", - ) - - - async def main() -> None: - await client.score_v_2.get_by_id( - score_id="scoreId", - ) - - - asyncio.run(main()) + AsyncHttpResponse[Score] """ _response = await self._client_wrapper.httpx_client.request( f"api/public/v2/scores/{jsonable_encoder(score_id)}", @@ -468,26 +549,78 @@ async def main() -> None: ) try: if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Score, _response.json()) # type: ignore + _data = typing.cast( + Score, + parse_obj_as( + type_=Score, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 401: raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 403: raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 405: raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) if _response.status_code == 404: raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) _response_json = _response.json() except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/score_v2/types/__init__.py b/langfuse/api/score_v2/types/__init__.py new file mode 100644 index 000000000..d54db47b8 --- /dev/null +++ b/langfuse/api/score_v2/types/__init__.py @@ -0,0 +1,70 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .get_scores_response import GetScoresResponse + from .get_scores_response_data import ( + GetScoresResponseData, + GetScoresResponseData_Boolean, + GetScoresResponseData_Categorical, + GetScoresResponseData_Numeric, + ) + from .get_scores_response_data_boolean import GetScoresResponseDataBoolean + from .get_scores_response_data_categorical import GetScoresResponseDataCategorical + from .get_scores_response_data_numeric import GetScoresResponseDataNumeric + from .get_scores_response_trace_data import GetScoresResponseTraceData +_dynamic_imports: typing.Dict[str, str] = { + "GetScoresResponse": ".get_scores_response", + "GetScoresResponseData": ".get_scores_response_data", + "GetScoresResponseDataBoolean": ".get_scores_response_data_boolean", + "GetScoresResponseDataCategorical": ".get_scores_response_data_categorical", + "GetScoresResponseDataNumeric": ".get_scores_response_data_numeric", + "GetScoresResponseData_Boolean": ".get_scores_response_data", + "GetScoresResponseData_Categorical": ".get_scores_response_data", + "GetScoresResponseData_Numeric": ".get_scores_response_data", + "GetScoresResponseTraceData": ".get_scores_response_trace_data", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = [ + "GetScoresResponse", + "GetScoresResponseData", + "GetScoresResponseDataBoolean", + "GetScoresResponseDataCategorical", + "GetScoresResponseDataNumeric", + "GetScoresResponseData_Boolean", + "GetScoresResponseData_Categorical", + "GetScoresResponseData_Numeric", + "GetScoresResponseTraceData", +] diff --git a/langfuse/api/score_v2/types/get_scores_response.py b/langfuse/api/score_v2/types/get_scores_response.py new file mode 100644 index 000000000..87e87e2aa --- /dev/null +++ b/langfuse/api/score_v2/types/get_scores_response.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse +from .get_scores_response_data import GetScoresResponseData + + +class GetScoresResponse(UniversalBaseModel): + data: typing.List[GetScoresResponseData] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/score_v2/types/get_scores_response_data.py b/langfuse/api/score_v2/types/get_scores_response_data.py new file mode 100644 index 000000000..2b15cafd4 --- /dev/null +++ b/langfuse/api/score_v2/types/get_scores_response_data.py @@ -0,0 +1,184 @@ +# This file was auto-generated by Fern from our API Definition. + +from __future__ import annotations + +import datetime as dt +import typing + +import pydantic +import typing_extensions +from ...commons.types.score_source import ScoreSource +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata +from .get_scores_response_trace_data import GetScoresResponseTraceData + + +class GetScoresResponseData_Numeric(UniversalBaseModel): + data_type: typing_extensions.Annotated[ + typing.Literal["NUMERIC"], FieldMetadata(alias="dataType") + ] = "NUMERIC" + trace: typing.Optional[GetScoresResponseTraceData] = None + value: float + id: str + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = None + session_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sessionId") + ] = None + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + dataset_run_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="datasetRunId") + ] = None + name: str + source: ScoreSource + timestamp: dt.datetime + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = None + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = None + environment: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class GetScoresResponseData_Categorical(UniversalBaseModel): + data_type: typing_extensions.Annotated[ + typing.Literal["CATEGORICAL"], FieldMetadata(alias="dataType") + ] = "CATEGORICAL" + trace: typing.Optional[GetScoresResponseTraceData] = None + value: float + string_value: typing_extensions.Annotated[str, FieldMetadata(alias="stringValue")] + id: str + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = None + session_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sessionId") + ] = None + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + dataset_run_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="datasetRunId") + ] = None + name: str + source: ScoreSource + timestamp: dt.datetime + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = None + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = None + environment: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +class GetScoresResponseData_Boolean(UniversalBaseModel): + data_type: typing_extensions.Annotated[ + typing.Literal["BOOLEAN"], FieldMetadata(alias="dataType") + ] = "BOOLEAN" + trace: typing.Optional[GetScoresResponseTraceData] = None + value: float + string_value: typing_extensions.Annotated[str, FieldMetadata(alias="stringValue")] + id: str + trace_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="traceId") + ] = None + session_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="sessionId") + ] = None + observation_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="observationId") + ] = None + dataset_run_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="datasetRunId") + ] = None + name: str + source: ScoreSource + timestamp: dt.datetime + created_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="createdAt") + ] + updated_at: typing_extensions.Annotated[ + dt.datetime, FieldMetadata(alias="updatedAt") + ] + author_user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="authorUserId") + ] = None + comment: typing.Optional[str] = None + metadata: typing.Optional[typing.Any] = None + config_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="configId") + ] = None + queue_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="queueId") + ] = None + environment: typing.Optional[str] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow + + +GetScoresResponseData = typing_extensions.Annotated[ + typing.Union[ + GetScoresResponseData_Numeric, + GetScoresResponseData_Categorical, + GetScoresResponseData_Boolean, + ], + pydantic.Field(discriminator="data_type"), +] diff --git a/langfuse/api/score_v2/types/get_scores_response_data_boolean.py b/langfuse/api/score_v2/types/get_scores_response_data_boolean.py new file mode 100644 index 000000000..0e406bcd6 --- /dev/null +++ b/langfuse/api/score_v2/types/get_scores_response_data_boolean.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.boolean_score import BooleanScore +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .get_scores_response_trace_data import GetScoresResponseTraceData + + +class GetScoresResponseDataBoolean(BooleanScore): + trace: typing.Optional[GetScoresResponseTraceData] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/score_v2/types/get_scores_response_data_categorical.py b/langfuse/api/score_v2/types/get_scores_response_data_categorical.py new file mode 100644 index 000000000..27b0ad0ab --- /dev/null +++ b/langfuse/api/score_v2/types/get_scores_response_data_categorical.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.categorical_score import CategoricalScore +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .get_scores_response_trace_data import GetScoresResponseTraceData + + +class GetScoresResponseDataCategorical(CategoricalScore): + trace: typing.Optional[GetScoresResponseTraceData] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/score_v2/types/get_scores_response_data_numeric.py b/langfuse/api/score_v2/types/get_scores_response_data_numeric.py new file mode 100644 index 000000000..38a686aaa --- /dev/null +++ b/langfuse/api/score_v2/types/get_scores_response_data_numeric.py @@ -0,0 +1,23 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.numeric_score import NumericScore +from ...core.pydantic_utilities import IS_PYDANTIC_V2 +from .get_scores_response_trace_data import GetScoresResponseTraceData + + +class GetScoresResponseDataNumeric(NumericScore): + trace: typing.Optional[GetScoresResponseTraceData] = None + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/score_v2/types/get_scores_response_trace_data.py b/langfuse/api/score_v2/types/get_scores_response_trace_data.py new file mode 100644 index 000000000..15145f6e8 --- /dev/null +++ b/langfuse/api/score_v2/types/get_scores_response_trace_data.py @@ -0,0 +1,38 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.serialization import FieldMetadata + + +class GetScoresResponseTraceData(UniversalBaseModel): + user_id: typing_extensions.Annotated[ + typing.Optional[str], FieldMetadata(alias="userId") + ] = pydantic.Field(default=None) + """ + The user ID associated with the trace referenced by score + """ + + tags: typing.Optional[typing.List[str]] = pydantic.Field(default=None) + """ + A list of tags associated with the trace referenced by score + """ + + environment: typing.Optional[str] = pydantic.Field(default=None) + """ + The environment of the trace referenced by score + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/sessions/__init__.py b/langfuse/api/sessions/__init__.py new file mode 100644 index 000000000..89b7e63bc --- /dev/null +++ b/langfuse/api/sessions/__init__.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import PaginatedSessions +_dynamic_imports: typing.Dict[str, str] = {"PaginatedSessions": ".types"} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["PaginatedSessions"] diff --git a/langfuse/api/sessions/client.py b/langfuse/api/sessions/client.py new file mode 100644 index 000000000..b99829feb --- /dev/null +++ b/langfuse/api/sessions/client.py @@ -0,0 +1,262 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ..commons.types.session_with_traces import SessionWithTraces +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawSessionsClient, RawSessionsClient +from .types.paginated_sessions import PaginatedSessions + + +class SessionsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawSessionsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawSessionsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawSessionsClient + """ + return self._raw_client + + def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + from_timestamp: typing.Optional[dt.datetime] = None, + to_timestamp: typing.Optional[dt.datetime] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedSessions: + """ + Get sessions + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1 + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. + + from_timestamp : typing.Optional[dt.datetime] + Optional filter to only include sessions created on or after a certain datetime (ISO 8601) + + to_timestamp : typing.Optional[dt.datetime] + Optional filter to only include sessions created before a certain datetime (ISO 8601) + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for sessions where the environment is one of the provided values. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedSessions + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.sessions.list() + """ + _response = self._raw_client.list( + page=page, + limit=limit, + from_timestamp=from_timestamp, + to_timestamp=to_timestamp, + environment=environment, + request_options=request_options, + ) + return _response.data + + def get( + self, + session_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> SessionWithTraces: + """ + Get a session. Please note that `traces` on this endpoint are not paginated, if you plan to fetch large sessions, consider `GET /api/public/traces?sessionId=` + + Parameters + ---------- + session_id : str + The unique id of a session + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SessionWithTraces + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.sessions.get( + session_id="sessionId", + ) + """ + _response = self._raw_client.get(session_id, request_options=request_options) + return _response.data + + +class AsyncSessionsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawSessionsClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawSessionsClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawSessionsClient + """ + return self._raw_client + + async def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + from_timestamp: typing.Optional[dt.datetime] = None, + to_timestamp: typing.Optional[dt.datetime] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> PaginatedSessions: + """ + Get sessions + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1 + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. + + from_timestamp : typing.Optional[dt.datetime] + Optional filter to only include sessions created on or after a certain datetime (ISO 8601) + + to_timestamp : typing.Optional[dt.datetime] + Optional filter to only include sessions created before a certain datetime (ISO 8601) + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for sessions where the environment is one of the provided values. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + PaginatedSessions + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.sessions.list() + + + asyncio.run(main()) + """ + _response = await self._raw_client.list( + page=page, + limit=limit, + from_timestamp=from_timestamp, + to_timestamp=to_timestamp, + environment=environment, + request_options=request_options, + ) + return _response.data + + async def get( + self, + session_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> SessionWithTraces: + """ + Get a session. Please note that `traces` on this endpoint are not paginated, if you plan to fetch large sessions, consider `GET /api/public/traces?sessionId=` + + Parameters + ---------- + session_id : str + The unique id of a session + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + SessionWithTraces + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.sessions.get( + session_id="sessionId", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.get( + session_id, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/sessions/raw_client.py b/langfuse/api/sessions/raw_client.py new file mode 100644 index 000000000..9c39a9a5a --- /dev/null +++ b/langfuse/api/sessions/raw_client.py @@ -0,0 +1,500 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..commons.types.session_with_traces import SessionWithTraces +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.datetime_utils import serialize_datetime +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.paginated_sessions import PaginatedSessions + + +class RawSessionsClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + from_timestamp: typing.Optional[dt.datetime] = None, + to_timestamp: typing.Optional[dt.datetime] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[PaginatedSessions]: + """ + Get sessions + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1 + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. + + from_timestamp : typing.Optional[dt.datetime] + Optional filter to only include sessions created on or after a certain datetime (ISO 8601) + + to_timestamp : typing.Optional[dt.datetime] + Optional filter to only include sessions created before a certain datetime (ISO 8601) + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for sessions where the environment is one of the provided values. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[PaginatedSessions] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/sessions", + method="GET", + params={ + "page": page, + "limit": limit, + "fromTimestamp": serialize_datetime(from_timestamp) + if from_timestamp is not None + else None, + "toTimestamp": serialize_datetime(to_timestamp) + if to_timestamp is not None + else None, + "environment": environment, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedSessions, + parse_obj_as( + type_=PaginatedSessions, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def get( + self, + session_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[SessionWithTraces]: + """ + Get a session. Please note that `traces` on this endpoint are not paginated, if you plan to fetch large sessions, consider `GET /api/public/traces?sessionId=` + + Parameters + ---------- + session_id : str + The unique id of a session + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[SessionWithTraces] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/sessions/{jsonable_encoder(session_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + SessionWithTraces, + parse_obj_as( + type_=SessionWithTraces, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawSessionsClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + from_timestamp: typing.Optional[dt.datetime] = None, + to_timestamp: typing.Optional[dt.datetime] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[PaginatedSessions]: + """ + Get sessions + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1 + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. + + from_timestamp : typing.Optional[dt.datetime] + Optional filter to only include sessions created on or after a certain datetime (ISO 8601) + + to_timestamp : typing.Optional[dt.datetime] + Optional filter to only include sessions created before a certain datetime (ISO 8601) + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for sessions where the environment is one of the provided values. + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[PaginatedSessions] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/sessions", + method="GET", + params={ + "page": page, + "limit": limit, + "fromTimestamp": serialize_datetime(from_timestamp) + if from_timestamp is not None + else None, + "toTimestamp": serialize_datetime(to_timestamp) + if to_timestamp is not None + else None, + "environment": environment, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + PaginatedSessions, + parse_obj_as( + type_=PaginatedSessions, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def get( + self, + session_id: str, + *, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[SessionWithTraces]: + """ + Get a session. Please note that `traces` on this endpoint are not paginated, if you plan to fetch large sessions, consider `GET /api/public/traces?sessionId=` + + Parameters + ---------- + session_id : str + The unique id of a session + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[SessionWithTraces] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/sessions/{jsonable_encoder(session_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + SessionWithTraces, + parse_obj_as( + type_=SessionWithTraces, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/sessions/types/__init__.py b/langfuse/api/sessions/types/__init__.py new file mode 100644 index 000000000..45f21e139 --- /dev/null +++ b/langfuse/api/sessions/types/__init__.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .paginated_sessions import PaginatedSessions +_dynamic_imports: typing.Dict[str, str] = {"PaginatedSessions": ".paginated_sessions"} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["PaginatedSessions"] diff --git a/langfuse/api/sessions/types/paginated_sessions.py b/langfuse/api/sessions/types/paginated_sessions.py new file mode 100644 index 000000000..21e97c06d --- /dev/null +++ b/langfuse/api/sessions/types/paginated_sessions.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.session import Session +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse + + +class PaginatedSessions(UniversalBaseModel): + data: typing.List[Session] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/trace/__init__.py b/langfuse/api/trace/__init__.py new file mode 100644 index 000000000..fc9889dfa --- /dev/null +++ b/langfuse/api/trace/__init__.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import DeleteTraceResponse, Sort, Traces +_dynamic_imports: typing.Dict[str, str] = { + "DeleteTraceResponse": ".types", + "Sort": ".types", + "Traces": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["DeleteTraceResponse", "Sort", "Traces"] diff --git a/langfuse/api/resources/trace/client.py b/langfuse/api/trace/client.py similarity index 61% rename from langfuse/api/resources/trace/client.py rename to langfuse/api/trace/client.py index e1f837f50..e5dcbb33c 100644 --- a/langfuse/api/resources/trace/client.py +++ b/langfuse/api/trace/client.py @@ -2,20 +2,11 @@ import datetime as dt import typing -from json.decoder import JSONDecodeError - -from ...core.api_error import ApiError -from ...core.client_wrapper import AsyncClientWrapper, SyncClientWrapper -from ...core.datetime_utils import serialize_datetime -from ...core.jsonable_encoder import jsonable_encoder -from ...core.pydantic_utilities import pydantic_v1 -from ...core.request_options import RequestOptions -from ..commons.errors.access_denied_error import AccessDeniedError -from ..commons.errors.error import Error -from ..commons.errors.method_not_allowed_error import MethodNotAllowedError -from ..commons.errors.not_found_error import NotFoundError -from ..commons.errors.unauthorized_error import UnauthorizedError + from ..commons.types.trace_with_full_details import TraceWithFullDetails +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawTraceClient, RawTraceClient from .types.delete_trace_response import DeleteTraceResponse from .types.traces import Traces @@ -25,7 +16,18 @@ class TraceClient: def __init__(self, *, client_wrapper: SyncClientWrapper): - self._client_wrapper = client_wrapper + self._raw_client = RawTraceClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawTraceClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawTraceClient + """ + return self._raw_client def get( self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None @@ -47,9 +49,9 @@ def get( Examples -------- - from langfuse.client import FernLangfuse + from langfuse import LangfuseAPI - client = FernLangfuse( + client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -61,36 +63,8 @@ def get( trace_id="traceId", ) """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/traces/{jsonable_encoder(trace_id)}", - method="GET", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(TraceWithFullDetails, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + _response = self._raw_client.get(trace_id, request_options=request_options) + return _response.data def delete( self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None @@ -112,9 +86,9 @@ def delete( Examples -------- - from langfuse.client import FernLangfuse + from langfuse import LangfuseAPI - client = FernLangfuse( + client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -126,36 +100,8 @@ def delete( trace_id="traceId", ) """ - _response = self._client_wrapper.httpx_client.request( - f"api/public/traces/{jsonable_encoder(trace_id)}", - method="DELETE", - request_options=request_options, - ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DeleteTraceResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + _response = self._raw_client.delete(trace_id, request_options=request_options) + return _response.data def list( self, @@ -333,9 +279,9 @@ def list( Examples -------- - from langfuse.client import FernLangfuse + from langfuse import LangfuseAPI - client = FernLangfuse( + client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -345,56 +291,24 @@ def list( ) client.trace.list() """ - _response = self._client_wrapper.httpx_client.request( - "api/public/traces", - method="GET", - params={ - "page": page, - "limit": limit, - "userId": user_id, - "name": name, - "sessionId": session_id, - "fromTimestamp": serialize_datetime(from_timestamp) - if from_timestamp is not None - else None, - "toTimestamp": serialize_datetime(to_timestamp) - if to_timestamp is not None - else None, - "orderBy": order_by, - "tags": tags, - "version": version, - "release": release, - "environment": environment, - "fields": fields, - "filter": filter, - }, + _response = self._raw_client.list( + page=page, + limit=limit, + user_id=user_id, + name=name, + session_id=session_id, + from_timestamp=from_timestamp, + to_timestamp=to_timestamp, + order_by=order_by, + tags=tags, + version=version, + release=release, + environment=environment, + fields=fields, + filter=filter, request_options=request_options, ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Traces, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data def delete_multiple( self, @@ -419,9 +333,9 @@ def delete_multiple( Examples -------- - from langfuse.client import FernLangfuse + from langfuse import LangfuseAPI - client = FernLangfuse( + client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -433,43 +347,26 @@ def delete_multiple( trace_ids=["traceIds", "traceIds"], ) """ - _response = self._client_wrapper.httpx_client.request( - "api/public/traces", - method="DELETE", - json={"traceIds": trace_ids}, - request_options=request_options, - omit=OMIT, + _response = self._raw_client.delete_multiple( + trace_ids=trace_ids, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DeleteTraceResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data class AsyncTraceClient: def __init__(self, *, client_wrapper: AsyncClientWrapper): - self._client_wrapper = client_wrapper + self._raw_client = AsyncRawTraceClient(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawTraceClient: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawTraceClient + """ + return self._raw_client async def get( self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None @@ -493,9 +390,9 @@ async def get( -------- import asyncio - from langfuse.client import AsyncFernLangfuse + from langfuse import AsyncLangfuseAPI - client = AsyncFernLangfuse( + client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -513,36 +410,10 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/traces/{jsonable_encoder(trace_id)}", - method="GET", - request_options=request_options, + _response = await self._raw_client.get( + trace_id, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(TraceWithFullDetails, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data async def delete( self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None @@ -566,9 +437,9 @@ async def delete( -------- import asyncio - from langfuse.client import AsyncFernLangfuse + from langfuse import AsyncLangfuseAPI - client = AsyncFernLangfuse( + client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -586,36 +457,10 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._client_wrapper.httpx_client.request( - f"api/public/traces/{jsonable_encoder(trace_id)}", - method="DELETE", - request_options=request_options, + _response = await self._raw_client.delete( + trace_id, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DeleteTraceResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data async def list( self, @@ -795,9 +640,9 @@ async def list( -------- import asyncio - from langfuse.client import AsyncFernLangfuse + from langfuse import AsyncLangfuseAPI - client = AsyncFernLangfuse( + client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -813,56 +658,24 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/traces", - method="GET", - params={ - "page": page, - "limit": limit, - "userId": user_id, - "name": name, - "sessionId": session_id, - "fromTimestamp": serialize_datetime(from_timestamp) - if from_timestamp is not None - else None, - "toTimestamp": serialize_datetime(to_timestamp) - if to_timestamp is not None - else None, - "orderBy": order_by, - "tags": tags, - "version": version, - "release": release, - "environment": environment, - "fields": fields, - "filter": filter, - }, + _response = await self._raw_client.list( + page=page, + limit=limit, + user_id=user_id, + name=name, + session_id=session_id, + from_timestamp=from_timestamp, + to_timestamp=to_timestamp, + order_by=order_by, + tags=tags, + version=version, + release=release, + environment=environment, + fields=fields, + filter=filter, request_options=request_options, ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(Traces, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data async def delete_multiple( self, @@ -889,9 +702,9 @@ async def delete_multiple( -------- import asyncio - from langfuse.client import AsyncFernLangfuse + from langfuse import AsyncLangfuseAPI - client = AsyncFernLangfuse( + client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", @@ -909,35 +722,7 @@ async def main() -> None: asyncio.run(main()) """ - _response = await self._client_wrapper.httpx_client.request( - "api/public/traces", - method="DELETE", - json={"traceIds": trace_ids}, - request_options=request_options, - omit=OMIT, + _response = await self._raw_client.delete_multiple( + trace_ids=trace_ids, request_options=request_options ) - try: - if 200 <= _response.status_code < 300: - return pydantic_v1.parse_obj_as(DeleteTraceResponse, _response.json()) # type: ignore - if _response.status_code == 400: - raise Error(pydantic_v1.parse_obj_as(typing.Any, _response.json())) # type: ignore - if _response.status_code == 401: - raise UnauthorizedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 403: - raise AccessDeniedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 405: - raise MethodNotAllowedError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - if _response.status_code == 404: - raise NotFoundError( - pydantic_v1.parse_obj_as(typing.Any, _response.json()) - ) # type: ignore - _response_json = _response.json() - except JSONDecodeError: - raise ApiError(status_code=_response.status_code, body=_response.text) - raise ApiError(status_code=_response.status_code, body=_response_json) + return _response.data diff --git a/langfuse/api/trace/raw_client.py b/langfuse/api/trace/raw_client.py new file mode 100644 index 000000000..10f3d15ec --- /dev/null +++ b/langfuse/api/trace/raw_client.py @@ -0,0 +1,1208 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..commons.types.trace_with_full_details import TraceWithFullDetails +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.datetime_utils import serialize_datetime +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.jsonable_encoder import jsonable_encoder +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.delete_trace_response import DeleteTraceResponse +from .types.traces import Traces + +# this is used as the default value for optional parameters +OMIT = typing.cast(typing.Any, ...) + + +class RawTraceClient: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get( + self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[TraceWithFullDetails]: + """ + Get a specific trace + + Parameters + ---------- + trace_id : str + The unique langfuse identifier of a trace + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[TraceWithFullDetails] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/traces/{jsonable_encoder(trace_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TraceWithFullDetails, + parse_obj_as( + type_=TraceWithFullDetails, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete( + self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[DeleteTraceResponse]: + """ + Delete a specific trace + + Parameters + ---------- + trace_id : str + The unique langfuse identifier of the trace to delete + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DeleteTraceResponse] + """ + _response = self._client_wrapper.httpx_client.request( + f"api/public/traces/{jsonable_encoder(trace_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteTraceResponse, + parse_obj_as( + type_=DeleteTraceResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + user_id: typing.Optional[str] = None, + name: typing.Optional[str] = None, + session_id: typing.Optional[str] = None, + from_timestamp: typing.Optional[dt.datetime] = None, + to_timestamp: typing.Optional[dt.datetime] = None, + order_by: typing.Optional[str] = None, + tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + version: typing.Optional[str] = None, + release: typing.Optional[str] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + fields: typing.Optional[str] = None, + filter: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[Traces]: + """ + Get list of traces + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1 + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. + + user_id : typing.Optional[str] + + name : typing.Optional[str] + + session_id : typing.Optional[str] + + from_timestamp : typing.Optional[dt.datetime] + Optional filter to only include traces with a trace.timestamp on or after a certain datetime (ISO 8601) + + to_timestamp : typing.Optional[dt.datetime] + Optional filter to only include traces with a trace.timestamp before a certain datetime (ISO 8601) + + order_by : typing.Optional[str] + Format of the string [field].[asc/desc]. Fields: id, timestamp, name, userId, release, version, public, bookmarked, sessionId. Example: timestamp.asc + + tags : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Only traces that include all of these tags will be returned. + + version : typing.Optional[str] + Optional filter to only include traces with a certain version. + + release : typing.Optional[str] + Optional filter to only include traces with a certain release. + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for traces where the environment is one of the provided values. + + fields : typing.Optional[str] + Comma-separated list of fields to include in the response. Available field groups: 'core' (always included), 'io' (input, output, metadata), 'scores', 'observations', 'metrics'. If not specified, all fields are returned. Example: 'core,scores,metrics'. Note: Excluded 'observations' or 'scores' fields return empty arrays; excluded 'metrics' returns -1 for 'totalCost' and 'latency'. + + filter : typing.Optional[str] + JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, sessionId, tags, version, release, environment, fromTimestamp, toTimestamp). + + ## Filter Structure + Each filter condition has the following structure: + ```json + [ + { + "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "column": string, // Required. Column to filter on (see available columns below) + "operator": string, // Required. Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - categoryOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject: "=", "contains", "does not contain", "starts with", "ends with" + // - numberObject: "=", ">", "<", ">=", "<=" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Required (except for null type). Value to compare against. Type depends on filter type + "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata + } + ] + ``` + + ## Available Columns + + ### Core Trace Fields + - `id` (string) - Trace ID + - `name` (string) - Trace name + - `timestamp` (datetime) - Trace timestamp + - `userId` (string) - User ID + - `sessionId` (string) - Session ID + - `environment` (string) - Environment tag + - `version` (string) - Version tag + - `release` (string) - Release tag + - `tags` (arrayOptions) - Array of tags + - `bookmarked` (boolean) - Bookmark status + + ### Structured Data + - `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys. + + ### Aggregated Metrics (from observations) + These metrics are aggregated from all observations within the trace: + - `latency` (number) - Latency in seconds (time from first observation start to last observation end) + - `inputTokens` (number) - Total input tokens across all observations + - `outputTokens` (number) - Total output tokens across all observations + - `totalTokens` (number) - Total tokens (alias: `tokens`) + - `inputCost` (number) - Total input cost in USD + - `outputCost` (number) - Total output cost in USD + - `totalCost` (number) - Total cost in USD + + ### Observation Level Aggregations + These fields aggregate observation levels within the trace: + - `level` (string) - Highest severity level (ERROR > WARNING > DEFAULT > DEBUG) + - `warningCount` (number) - Count of WARNING level observations + - `errorCount` (number) - Count of ERROR level observations + - `defaultCount` (number) - Count of DEFAULT level observations + - `debugCount` (number) - Count of DEBUG level observations + + ### Scores (requires join with scores table) + - `scores_avg` (number) - Average of numeric scores (alias: `scores`) + - `score_categories` (categoryOptions) - Categorical score values + + ## Filter Examples + ```json + [ + { + "type": "datetime", + "column": "timestamp", + "operator": ">=", + "value": "2024-01-01T00:00:00Z" + }, + { + "type": "string", + "column": "userId", + "operator": "=", + "value": "user-123" + }, + { + "type": "number", + "column": "totalCost", + "operator": ">=", + "value": 0.01 + }, + { + "type": "arrayOptions", + "column": "tags", + "operator": "all of", + "value": ["production", "critical"] + }, + { + "type": "stringObject", + "column": "metadata", + "key": "customer_tier", + "operator": "=", + "value": "enterprise" + } + ] + ``` + + ## Performance Notes + - Filtering on `userId`, `sessionId`, or `metadata` may enable skip indexes for better query performance + - Score filters require a join with the scores table and may impact query performance + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[Traces] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/traces", + method="GET", + params={ + "page": page, + "limit": limit, + "userId": user_id, + "name": name, + "sessionId": session_id, + "fromTimestamp": serialize_datetime(from_timestamp) + if from_timestamp is not None + else None, + "toTimestamp": serialize_datetime(to_timestamp) + if to_timestamp is not None + else None, + "orderBy": order_by, + "tags": tags, + "version": version, + "release": release, + "environment": environment, + "fields": fields, + "filter": filter, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Traces, + parse_obj_as( + type_=Traces, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + def delete_multiple( + self, + *, + trace_ids: typing.Sequence[str], + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[DeleteTraceResponse]: + """ + Delete multiple traces + + Parameters + ---------- + trace_ids : typing.Sequence[str] + List of trace IDs to delete + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[DeleteTraceResponse] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/traces", + method="DELETE", + json={ + "traceIds": trace_ids, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteTraceResponse, + parse_obj_as( + type_=DeleteTraceResponse, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawTraceClient: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get( + self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[TraceWithFullDetails]: + """ + Get a specific trace + + Parameters + ---------- + trace_id : str + The unique langfuse identifier of a trace + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[TraceWithFullDetails] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/traces/{jsonable_encoder(trace_id)}", + method="GET", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + TraceWithFullDetails, + parse_obj_as( + type_=TraceWithFullDetails, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete( + self, trace_id: str, *, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[DeleteTraceResponse]: + """ + Delete a specific trace + + Parameters + ---------- + trace_id : str + The unique langfuse identifier of the trace to delete + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DeleteTraceResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + f"api/public/traces/{jsonable_encoder(trace_id)}", + method="DELETE", + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteTraceResponse, + parse_obj_as( + type_=DeleteTraceResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def list( + self, + *, + page: typing.Optional[int] = None, + limit: typing.Optional[int] = None, + user_id: typing.Optional[str] = None, + name: typing.Optional[str] = None, + session_id: typing.Optional[str] = None, + from_timestamp: typing.Optional[dt.datetime] = None, + to_timestamp: typing.Optional[dt.datetime] = None, + order_by: typing.Optional[str] = None, + tags: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + version: typing.Optional[str] = None, + release: typing.Optional[str] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + fields: typing.Optional[str] = None, + filter: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[Traces]: + """ + Get list of traces + + Parameters + ---------- + page : typing.Optional[int] + Page number, starts at 1 + + limit : typing.Optional[int] + Limit of items per page. If you encounter api issues due to too large page sizes, try to reduce the limit. + + user_id : typing.Optional[str] + + name : typing.Optional[str] + + session_id : typing.Optional[str] + + from_timestamp : typing.Optional[dt.datetime] + Optional filter to only include traces with a trace.timestamp on or after a certain datetime (ISO 8601) + + to_timestamp : typing.Optional[dt.datetime] + Optional filter to only include traces with a trace.timestamp before a certain datetime (ISO 8601) + + order_by : typing.Optional[str] + Format of the string [field].[asc/desc]. Fields: id, timestamp, name, userId, release, version, public, bookmarked, sessionId. Example: timestamp.asc + + tags : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Only traces that include all of these tags will be returned. + + version : typing.Optional[str] + Optional filter to only include traces with a certain version. + + release : typing.Optional[str] + Optional filter to only include traces with a certain release. + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for traces where the environment is one of the provided values. + + fields : typing.Optional[str] + Comma-separated list of fields to include in the response. Available field groups: 'core' (always included), 'io' (input, output, metadata), 'scores', 'observations', 'metrics'. If not specified, all fields are returned. Example: 'core,scores,metrics'. Note: Excluded 'observations' or 'scores' fields return empty arrays; excluded 'metrics' returns -1 for 'totalCost' and 'latency'. + + filter : typing.Optional[str] + JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, sessionId, tags, version, release, environment, fromTimestamp, toTimestamp). + + ## Filter Structure + Each filter condition has the following structure: + ```json + [ + { + "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "column": string, // Required. Column to filter on (see available columns below) + "operator": string, // Required. Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - categoryOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject: "=", "contains", "does not contain", "starts with", "ends with" + // - numberObject: "=", ">", "<", ">=", "<=" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Required (except for null type). Value to compare against. Type depends on filter type + "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata + } + ] + ``` + + ## Available Columns + + ### Core Trace Fields + - `id` (string) - Trace ID + - `name` (string) - Trace name + - `timestamp` (datetime) - Trace timestamp + - `userId` (string) - User ID + - `sessionId` (string) - Session ID + - `environment` (string) - Environment tag + - `version` (string) - Version tag + - `release` (string) - Release tag + - `tags` (arrayOptions) - Array of tags + - `bookmarked` (boolean) - Bookmark status + + ### Structured Data + - `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys. + + ### Aggregated Metrics (from observations) + These metrics are aggregated from all observations within the trace: + - `latency` (number) - Latency in seconds (time from first observation start to last observation end) + - `inputTokens` (number) - Total input tokens across all observations + - `outputTokens` (number) - Total output tokens across all observations + - `totalTokens` (number) - Total tokens (alias: `tokens`) + - `inputCost` (number) - Total input cost in USD + - `outputCost` (number) - Total output cost in USD + - `totalCost` (number) - Total cost in USD + + ### Observation Level Aggregations + These fields aggregate observation levels within the trace: + - `level` (string) - Highest severity level (ERROR > WARNING > DEFAULT > DEBUG) + - `warningCount` (number) - Count of WARNING level observations + - `errorCount` (number) - Count of ERROR level observations + - `defaultCount` (number) - Count of DEFAULT level observations + - `debugCount` (number) - Count of DEBUG level observations + + ### Scores (requires join with scores table) + - `scores_avg` (number) - Average of numeric scores (alias: `scores`) + - `score_categories` (categoryOptions) - Categorical score values + + ## Filter Examples + ```json + [ + { + "type": "datetime", + "column": "timestamp", + "operator": ">=", + "value": "2024-01-01T00:00:00Z" + }, + { + "type": "string", + "column": "userId", + "operator": "=", + "value": "user-123" + }, + { + "type": "number", + "column": "totalCost", + "operator": ">=", + "value": 0.01 + }, + { + "type": "arrayOptions", + "column": "tags", + "operator": "all of", + "value": ["production", "critical"] + }, + { + "type": "stringObject", + "column": "metadata", + "key": "customer_tier", + "operator": "=", + "value": "enterprise" + } + ] + ``` + + ## Performance Notes + - Filtering on `userId`, `sessionId`, or `metadata` may enable skip indexes for better query performance + - Score filters require a join with the scores table and may impact query performance + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[Traces] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/traces", + method="GET", + params={ + "page": page, + "limit": limit, + "userId": user_id, + "name": name, + "sessionId": session_id, + "fromTimestamp": serialize_datetime(from_timestamp) + if from_timestamp is not None + else None, + "toTimestamp": serialize_datetime(to_timestamp) + if to_timestamp is not None + else None, + "orderBy": order_by, + "tags": tags, + "version": version, + "release": release, + "environment": environment, + "fields": fields, + "filter": filter, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + Traces, + parse_obj_as( + type_=Traces, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + async def delete_multiple( + self, + *, + trace_ids: typing.Sequence[str], + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[DeleteTraceResponse]: + """ + Delete multiple traces + + Parameters + ---------- + trace_ids : typing.Sequence[str] + List of trace IDs to delete + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[DeleteTraceResponse] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/traces", + method="DELETE", + json={ + "traceIds": trace_ids, + }, + request_options=request_options, + omit=OMIT, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + DeleteTraceResponse, + parse_obj_as( + type_=DeleteTraceResponse, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/trace/types/__init__.py b/langfuse/api/trace/types/__init__.py new file mode 100644 index 000000000..3eab30d21 --- /dev/null +++ b/langfuse/api/trace/types/__init__.py @@ -0,0 +1,46 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .delete_trace_response import DeleteTraceResponse + from .sort import Sort + from .traces import Traces +_dynamic_imports: typing.Dict[str, str] = { + "DeleteTraceResponse": ".delete_trace_response", + "Sort": ".sort", + "Traces": ".traces", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["DeleteTraceResponse", "Sort", "Traces"] diff --git a/langfuse/api/trace/types/delete_trace_response.py b/langfuse/api/trace/types/delete_trace_response.py new file mode 100644 index 000000000..b505fd68d --- /dev/null +++ b/langfuse/api/trace/types/delete_trace_response.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class DeleteTraceResponse(UniversalBaseModel): + message: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/trace/types/sort.py b/langfuse/api/trace/types/sort.py new file mode 100644 index 000000000..0949f598d --- /dev/null +++ b/langfuse/api/trace/types/sort.py @@ -0,0 +1,21 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class Sort(UniversalBaseModel): + id: str + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/trace/types/traces.py b/langfuse/api/trace/types/traces.py new file mode 100644 index 000000000..2f0e02f43 --- /dev/null +++ b/langfuse/api/trace/types/traces.py @@ -0,0 +1,24 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...commons.types.trace_with_details import TraceWithDetails +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...utils.pagination.types.meta_response import MetaResponse + + +class Traces(UniversalBaseModel): + data: typing.List[TraceWithDetails] + meta: MetaResponse + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/utils/__init__.py b/langfuse/api/utils/__init__.py new file mode 100644 index 000000000..b272f64b5 --- /dev/null +++ b/langfuse/api/utils/__init__.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from . import pagination + from .pagination import MetaResponse +_dynamic_imports: typing.Dict[str, str] = { + "MetaResponse": ".pagination", + "pagination": ".pagination", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["MetaResponse", "pagination"] diff --git a/langfuse/api/utils/pagination/__init__.py b/langfuse/api/utils/pagination/__init__.py new file mode 100644 index 000000000..50821832d --- /dev/null +++ b/langfuse/api/utils/pagination/__init__.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import MetaResponse +_dynamic_imports: typing.Dict[str, str] = {"MetaResponse": ".types"} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["MetaResponse"] diff --git a/langfuse/api/utils/pagination/types/__init__.py b/langfuse/api/utils/pagination/types/__init__.py new file mode 100644 index 000000000..5c0d83028 --- /dev/null +++ b/langfuse/api/utils/pagination/types/__init__.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .meta_response import MetaResponse +_dynamic_imports: typing.Dict[str, str] = {"MetaResponse": ".meta_response"} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["MetaResponse"] diff --git a/langfuse/api/utils/pagination/types/meta_response.py b/langfuse/api/utils/pagination/types/meta_response.py new file mode 100644 index 000000000..7b9169efd --- /dev/null +++ b/langfuse/api/utils/pagination/types/meta_response.py @@ -0,0 +1,45 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +import typing_extensions +from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ....core.serialization import FieldMetadata + + +class MetaResponse(UniversalBaseModel): + page: int = pydantic.Field() + """ + current page number + """ + + limit: int = pydantic.Field() + """ + number of items per page + """ + + total_items: typing_extensions.Annotated[int, FieldMetadata(alias="totalItems")] = ( + pydantic.Field() + ) + """ + number of total items given the current filters/selection (if any) + """ + + total_pages: typing_extensions.Annotated[int, FieldMetadata(alias="totalPages")] = ( + pydantic.Field() + ) + """ + number of total pages given the current limit + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/batch_evaluation.py b/langfuse/batch_evaluation.py index 35e1ea938..391334b66 100644 --- a/langfuse/batch_evaluation.py +++ b/langfuse/batch_evaluation.py @@ -22,7 +22,7 @@ Union, ) -from langfuse.api.resources.commons.types import ( +from langfuse.api.commons import ( ObservationsView, TraceWithFullDetails, ) diff --git a/langfuse/langchain/CallbackHandler.py b/langfuse/langchain/CallbackHandler.py index 7f6479867..a2dd43a9e 100644 --- a/langfuse/langchain/CallbackHandler.py +++ b/langfuse/langchain/CallbackHandler.py @@ -1210,7 +1210,9 @@ def _parse_usage_model(usage: Union[pydantic.BaseModel, dict]) -> Any: usage_model["input"] = max(0, usage_model["input"] - value) if f"input_modality_{item['modality']}" in usage_model: - usage_model[f"input_modality_{item['modality']}"] = max(0, usage_model[f"input_modality_{item['modality']}"] - value) + usage_model[f"input_modality_{item['modality']}"] = max( + 0, usage_model[f"input_modality_{item['modality']}"] - value + ) usage_model = {k: v for k, v in usage_model.items() if isinstance(v, int)} diff --git a/langfuse/model.py b/langfuse/model.py index 75803d215..fb13d712e 100644 --- a/langfuse/model.py +++ b/langfuse/model.py @@ -4,52 +4,35 @@ from abc import ABC, abstractmethod from typing import Any, Dict, List, Literal, Optional, Sequence, Tuple, TypedDict, Union -from langfuse.api.resources.commons.types.dataset import ( - Dataset, # noqa: F401 +from langfuse.api.commons import ( # noqa: F401 + MapValue, + Observation, + TraceWithFullDetails, ) # these imports need to stay here, otherwise imports from our clients wont work -from langfuse.api.resources.commons.types.dataset_item import DatasetItem # noqa: F401 - -# noqa: F401 -from langfuse.api.resources.commons.types.dataset_run import DatasetRun # noqa: F401 - -# noqa: F401 -from langfuse.api.resources.commons.types.dataset_status import ( # noqa: F401 - DatasetStatus, -) -from langfuse.api.resources.commons.types.map_value import MapValue # noqa: F401 -from langfuse.api.resources.commons.types.observation import Observation # noqa: F401 -from langfuse.api.resources.commons.types.trace_with_full_details import ( # noqa: F401 - TraceWithFullDetails, +from langfuse.api.dataset_items import ( # noqa: F401 + CreateDatasetItemRequest, + DatasetItem, # noqa: F401 ) # noqa: F401 -from langfuse.api.resources.dataset_items.types.create_dataset_item_request import ( # noqa: F401 - CreateDatasetItemRequest, -) -from langfuse.api.resources.dataset_run_items.types.create_dataset_run_item_request import ( # noqa: F401 +from langfuse.api.dataset_run_items import ( # noqa: F401 CreateDatasetRunItemRequest, + DatasetRun, # noqa: F401 ) # noqa: F401 -from langfuse.api.resources.datasets.types.create_dataset_request import ( # noqa: F401 +# noqa: F401 +from langfuse.api.datasets import ( # noqa: F401 # noqa: F401 CreateDatasetRequest, + Dataset, # noqa: F401 + DatasetStatus, ) -from langfuse.api.resources.prompts import Prompt, Prompt_Chat, Prompt_Text +from langfuse.api.prompts import Prompt, Prompt_Chat, Prompt_Text from langfuse.logger import langfuse_logger -class ModelUsage(TypedDict): - unit: Optional[str] - input: Optional[int] - output: Optional[int] - total: Optional[int] - input_cost: Optional[float] - output_cost: Optional[float] - total_cost: Optional[float] - - class ChatMessageDict(TypedDict): role: str content: str diff --git a/langfuse/types.py b/langfuse/types.py index 32ebb32d4..99c9b355b 100644 --- a/langfuse/types.py +++ b/langfuse/types.py @@ -26,7 +26,6 @@ def my_evaluator(*, output: str, **kwargs) -> Evaluation: Optional, Protocol, TypedDict, - Union, ) try: @@ -34,10 +33,9 @@ def my_evaluator(*, output: str, **kwargs) -> Evaluation: except ImportError: from typing_extensions import NotRequired -from pydantic import BaseModel from langfuse.api import MediaContentType, UsageDetails -from langfuse.model import MapValue, ModelUsage, PromptClient +from langfuse.model import MapValue, PromptClient SpanLevel = Literal["DEBUG", "DEFAULT", "WARNING", "ERROR"] @@ -65,7 +63,6 @@ class ObservationParams(TraceMetadata, TypedDict): completion_start_time: Optional[datetime] model: Optional[str] model_parameters: Optional[Dict[str, MapValue]] - usage: Optional[Union[BaseModel, ModelUsage]] usage_details: Optional[UsageDetails] cost_details: Optional[Dict[str, float]] prompt: Optional[PromptClient] diff --git a/pyproject.toml b/pyproject.toml index 97866a2bc..e6d623499 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ readme = "README.md" [tool.poetry.dependencies] python = ">=3.10,<4.0" httpx = ">=0.15.4,<1.0" -pydantic = ">=1.10.7, <3.0" +pydantic = "^2" backoff = ">=1.10.0" openai = { version = ">=0.27.8", optional = true } wrapt = "^1.14" @@ -95,9 +95,7 @@ ignore_missing_imports = true [[tool.mypy.overrides]] module = [ - "langfuse.api.resources.*", - "langfuse.api.core.*", - "langfuse.api.client" + "langfuse.api.*", ] ignore_errors = true diff --git a/tests/test_prompt.py b/tests/test_prompt.py index bc3a5b7eb..6ba5ab85a 100644 --- a/tests/test_prompt.py +++ b/tests/test_prompt.py @@ -682,7 +682,7 @@ def test_prompt_end_to_end(): @pytest.fixture def langfuse(): from langfuse._client.resource_manager import LangfuseResourceManager - + langfuse_instance = Langfuse() langfuse_instance.api = Mock() diff --git a/tests/utils.py b/tests/utils.py index b6aeeb185..1e3ee28a3 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -9,7 +9,7 @@ except ImportError: import pydantic # type: ignore -from langfuse.api.client import FernLangfuse +from langfuse.api.client import LangfuseAPI def create_uuid(): @@ -19,7 +19,7 @@ def create_uuid(): def get_api(): sleep(2) - return FernLangfuse( + return LangfuseAPI( username=os.environ.get("LANGFUSE_PUBLIC_KEY"), password=os.environ.get("LANGFUSE_SECRET_KEY"), base_url=os.environ.get("LANGFUSE_BASE_URL"), From dbce49016f30bfc8da9dba2890bc766b2b062537 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Wed, 17 Dec 2025 18:30:09 +0100 Subject: [PATCH 02/15] push --- poetry.lock | 1719 +++++++++++++++++++++++++-------------------------- 1 file changed, 852 insertions(+), 867 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1ff0fca7f..775820966 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "annotated-types" @@ -6,7 +6,6 @@ version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, @@ -14,24 +13,22 @@ files = [ [[package]] name = "anyio" -version = "4.11.0" +version = "4.12.0" description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ - {file = "anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc"}, - {file = "anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4"}, + {file = "anyio-4.12.0-py3-none-any.whl", hash = "sha256:dad2376a628f98eeca4881fc56cd06affd18f659b17a747d3ff0307ced94b1bb"}, + {file = "anyio-4.12.0.tar.gz", hash = "sha256:73c693b567b0c55130c104d0b43a9baf3aa6a31fc6110116509f27bf75e21ec0"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" -sniffio = ">=1.1" typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -trio = ["trio (>=0.31.0)"] +trio = ["trio (>=0.31.0)", "trio (>=0.32.0)"] [[package]] name = "attrs" @@ -39,7 +36,6 @@ version = "25.4.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373"}, {file = "attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11"}, @@ -51,7 +47,6 @@ version = "0.0.130" description = "Universal library for evaluating AI models" optional = false python-versions = ">=3.8.0" -groups = ["dev"] files = [ {file = "autoevals-0.0.130-py3-none-any.whl", hash = "sha256:ffb7b3a21070d2a4e593bb118180c04e43531e608bffd854624377bd857ceec0"}, {file = "autoevals-0.0.130.tar.gz", hash = "sha256:92f87ab95a575b56d9d7377e6f1399932d09180d2f3a8266b4f693f46f49b86d"}, @@ -75,7 +70,6 @@ version = "2.2.1" description = "Function decoration for backoff and retry" optional = false python-versions = ">=3.7,<4.0" -groups = ["main"] files = [ {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, @@ -87,8 +81,6 @@ version = "1.2.0" description = "Backport of asyncio.Runner, a context manager that controls event loop life cycle." optional = false python-versions = "<3.11,>=3.8" -groups = ["dev"] -markers = "python_version == \"3.10\"" files = [ {file = "backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5"}, {file = "backports_asyncio_runner-1.2.0.tar.gz", hash = "sha256:a5aa7b2b7d8f8bfcaa2b57313f70792df84e32a2a746f585213373f900b42162"}, @@ -96,26 +88,24 @@ files = [ [[package]] name = "certifi" -version = "2025.10.5" +version = "2025.11.12" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ - {file = "certifi-2025.10.5-py3-none-any.whl", hash = "sha256:0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de"}, - {file = "certifi-2025.10.5.tar.gz", hash = "sha256:47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43"}, + {file = "certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b"}, + {file = "certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316"}, ] [[package]] name = "cfgv" -version = "3.4.0" +version = "3.5.0" description = "Validate configuration and produce human readable error messages." optional = false -python-versions = ">=3.8" -groups = ["dev"] +python-versions = ">=3.10" files = [ - {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, - {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, + {file = "cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0"}, + {file = "cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132"}, ] [[package]] @@ -124,7 +114,6 @@ version = "3.4.4" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d"}, {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8"}, @@ -247,7 +236,6 @@ version = "0.14.0" description = "Mustache templating language renderer" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "chevron-0.14.0-py3-none-any.whl", hash = "sha256:fbf996a709f8da2e745ef763f482ce2d311aa817d287593a5b990d6d6e4f0443"}, {file = "chevron-0.14.0.tar.gz", hash = "sha256:87613aafdf6d77b6a90ff073165a61ae5086e21ad49057aa0e53681601800ebf"}, @@ -259,12 +247,10 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {main = "platform_system == \"Windows\"", dev = "platform_system == \"Windows\" or sys_platform == \"win32\""} [[package]] name = "distlib" @@ -272,7 +258,6 @@ version = "0.4.0" description = "Distribution utilities" optional = false python-versions = "*" -groups = ["dev"] files = [ {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, @@ -284,7 +269,6 @@ version = "1.9.0" description = "Distro - an OS platform information API" optional = false python-versions = ">=3.6" -groups = ["main", "dev"] files = [ {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"}, {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"}, @@ -292,15 +276,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.3.0" +version = "1.3.1" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] -markers = "python_version == \"3.10\"" files = [ - {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, - {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, ] [package.dependencies] @@ -311,14 +293,13 @@ test = ["pytest (>=6)"] [[package]] name = "execnet" -version = "2.1.1" +version = "2.1.2" description = "execnet: rapid multi-Python deployment" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ - {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, - {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, + {file = "execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec"}, + {file = "execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd"}, ] [package.extras] @@ -330,7 +311,6 @@ version = "3.20.1" description = "A platform independent file lock." optional = false python-versions = ">=3.10" -groups = ["dev"] files = [ {file = "filelock-3.20.1-py3-none-any.whl", hash = "sha256:15d9e9a67306188a44baa72f569d2bfd803076269365fdea0934385da4dc361a"}, {file = "filelock-3.20.1.tar.gz", hash = "sha256:b8360948b351b80f420878d8516519a2204b07aefcdcfd24912a5d33127f188c"}, @@ -338,14 +318,13 @@ files = [ [[package]] name = "googleapis-common-protos" -version = "1.70.0" +version = "1.72.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" -groups = ["main"] files = [ - {file = "googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8"}, - {file = "googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257"}, + {file = "googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038"}, + {file = "googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5"}, ] [package.dependencies] @@ -360,7 +339,6 @@ version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, @@ -372,7 +350,6 @@ version = "1.0.9" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, @@ -394,7 +371,6 @@ version = "0.28.1" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, @@ -407,7 +383,7 @@ httpcore = "==1.*" idna = "*" [package.extras] -brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +brotli = ["brotli", "brotlicffi"] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] @@ -419,7 +395,6 @@ version = "2.6.15" description = "File identification library for Python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757"}, {file = "identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf"}, @@ -434,7 +409,6 @@ version = "3.11" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, @@ -449,7 +423,6 @@ version = "8.7.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, @@ -459,12 +432,12 @@ files = [ zipp = ">=3.20" [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] type = ["pytest-mypy"] [[package]] @@ -473,7 +446,6 @@ version = "2.3.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.10" -groups = ["dev"] files = [ {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, @@ -485,7 +457,6 @@ version = "3.1.6" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" -groups = ["docs"] files = [ {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, @@ -499,114 +470,113 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jiter" -version = "0.11.1" +version = "0.12.0" description = "Fast iterable JSON parser." optional = false python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "jiter-0.11.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ed58841a491bbbf3f7c55a6b68fff568439ab73b2cce27ace0e169057b5851df"}, - {file = "jiter-0.11.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:499beb9b2d7e51d61095a8de39ebcab1d1778f2a74085f8305a969f6cee9f3e4"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b87b2821795e28cc990939b68ce7a038edea680a24910bd68a79d54ff3f03c02"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:83f6fa494d8bba14ab100417c80e70d32d737e805cb85be2052d771c76fcd1f8"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fbc6aea1daa2ec6f5ed465f0c5e7b0607175062ceebbea5ca70dd5ddab58083"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:302288e2edc43174bb2db838e94688d724f9aad26c5fb9a74f7a5fb427452a6a"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85db563fe3b367bb568af5d29dea4d4066d923b8e01f3417d25ebecd958de815"}, - {file = "jiter-0.11.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f1c1ba2b6b22f775444ef53bc2d5778396d3520abc7b2e1da8eb0c27cb3ffb10"}, - {file = "jiter-0.11.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:523be464b14f8fd0cc78da6964b87b5515a056427a2579f9085ce30197a1b54a"}, - {file = "jiter-0.11.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:25b99b3f04cd2a38fefb22e822e35eb203a2cd37d680dbbc0c0ba966918af336"}, - {file = "jiter-0.11.1-cp310-cp310-win32.whl", hash = "sha256:47a79e90545a596bb9104109777894033347b11180d4751a216afef14072dbe7"}, - {file = "jiter-0.11.1-cp310-cp310-win_amd64.whl", hash = "sha256:cace75621ae9bd66878bf69fbd4dfc1a28ef8661e0c2d0eb72d3d6f1268eddf5"}, - {file = "jiter-0.11.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9b0088ff3c374ce8ce0168523ec8e97122ebb788f950cf7bb8e39c7dc6a876a2"}, - {file = "jiter-0.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74433962dd3c3090655e02e461267095d6c84f0741c7827de11022ef8d7ff661"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d98030e345e6546df2cc2c08309c502466c66c4747b043f1a0d415fada862b8"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1d6db0b2e788db46bec2cf729a88b6dd36959af2abd9fa2312dfba5acdd96dcb"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55678fbbda261eafe7289165dd2ddd0e922df5f9a1ae46d7c79a5a15242bd7d1"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a6b74fae8e40497653b52ce6ca0f1b13457af769af6fb9c1113efc8b5b4d9be"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a55a453f8b035eb4f7852a79a065d616b7971a17f5e37a9296b4b38d3b619e4"}, - {file = "jiter-0.11.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2638148099022e6bdb3f42904289cd2e403609356fb06eb36ddec2d50958bc29"}, - {file = "jiter-0.11.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:252490567a5d990986f83b95a5f1ca1bf205ebd27b3e9e93bb7c2592380e29b9"}, - {file = "jiter-0.11.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d431d52b0ca2436eea6195f0f48528202100c7deda354cb7aac0a302167594d5"}, - {file = "jiter-0.11.1-cp311-cp311-win32.whl", hash = "sha256:db6f41e40f8bae20c86cb574b48c4fd9f28ee1c71cb044e9ec12e78ab757ba3a"}, - {file = "jiter-0.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:0cc407b8e6cdff01b06bb80f61225c8b090c3df108ebade5e0c3c10993735b19"}, - {file = "jiter-0.11.1-cp311-cp311-win_arm64.whl", hash = "sha256:fe04ea475392a91896d1936367854d346724a1045a247e5d1c196410473b8869"}, - {file = "jiter-0.11.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c92148eec91052538ce6823dfca9525f5cfc8b622d7f07e9891a280f61b8c96c"}, - {file = "jiter-0.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ecd4da91b5415f183a6be8f7158d127bdd9e6a3174138293c0d48d6ea2f2009d"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7e3ac25c00b9275684d47aa42febaa90a9958e19fd1726c4ecf755fbe5e553b"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:57d7305c0a841858f866cd459cd9303f73883fb5e097257f3d4a3920722c69d4"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e86fa10e117dce22c547f31dd6d2a9a222707d54853d8de4e9a2279d2c97f239"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ae5ef1d48aec7e01ee8420155d901bb1d192998fa811a65ebb82c043ee186711"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb68e7bf65c990531ad8715e57d50195daf7c8e6f1509e617b4e692af1108939"}, - {file = "jiter-0.11.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43b30c8154ded5845fa454ef954ee67bfccce629b2dea7d01f795b42bc2bda54"}, - {file = "jiter-0.11.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:586cafbd9dd1f3ce6a22b4a085eaa6be578e47ba9b18e198d4333e598a91db2d"}, - {file = "jiter-0.11.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:677cc2517d437a83bb30019fd4cf7cad74b465914c56ecac3440d597ac135250"}, - {file = "jiter-0.11.1-cp312-cp312-win32.whl", hash = "sha256:fa992af648fcee2b850a3286a35f62bbbaeddbb6dbda19a00d8fbc846a947b6e"}, - {file = "jiter-0.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:88b5cae9fa51efeb3d4bd4e52bfd4c85ccc9cac44282e2a9640893a042ba4d87"}, - {file = "jiter-0.11.1-cp312-cp312-win_arm64.whl", hash = "sha256:9a6cae1ab335551917f882f2c3c1efe7617b71b4c02381e4382a8fc80a02588c"}, - {file = "jiter-0.11.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:71b6a920a5550f057d49d0e8bcc60945a8da998019e83f01adf110e226267663"}, - {file = "jiter-0.11.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b3de72e925388453a5171be83379549300db01284f04d2a6f244d1d8de36f94"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc19dd65a2bd3d9c044c5b4ebf657ca1e6003a97c0fc10f555aa4f7fb9821c00"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d58faaa936743cd1464540562f60b7ce4fd927e695e8bc31b3da5b914baa9abd"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:902640c3103625317291cb73773413b4d71847cdf9383ba65528745ff89f1d14"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:30405f726e4c2ed487b176c09f8b877a957f535d60c1bf194abb8dadedb5836f"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3217f61728b0baadd2551844870f65219ac4a1285d5e1a4abddff3d51fdabe96"}, - {file = "jiter-0.11.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b1364cc90c03a8196f35f396f84029f12abe925415049204446db86598c8b72c"}, - {file = "jiter-0.11.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:53a54bf8e873820ab186b2dca9f6c3303f00d65ae5e7b7d6bda1b95aa472d646"}, - {file = "jiter-0.11.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7e29aca023627b0e0c2392d4248f6414d566ff3974fa08ff2ac8dbb96dfee92a"}, - {file = "jiter-0.11.1-cp313-cp313-win32.whl", hash = "sha256:f153e31d8bca11363751e875c0a70b3d25160ecbaee7b51e457f14498fb39d8b"}, - {file = "jiter-0.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:f773f84080b667c69c4ea0403fc67bb08b07e2b7ce1ef335dea5868451e60fed"}, - {file = "jiter-0.11.1-cp313-cp313-win_arm64.whl", hash = "sha256:635ecd45c04e4c340d2187bcb1cea204c7cc9d32c1364d251564bf42e0e39c2d"}, - {file = "jiter-0.11.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d892b184da4d94d94ddb4031296931c74ec8b325513a541ebfd6dfb9ae89904b"}, - {file = "jiter-0.11.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa22c223a3041dacb2fcd37c70dfd648b44662b4a48e242592f95bda5ab09d58"}, - {file = "jiter-0.11.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:330e8e6a11ad4980cd66a0f4a3e0e2e0f646c911ce047014f984841924729789"}, - {file = "jiter-0.11.1-cp313-cp313t-win_amd64.whl", hash = "sha256:09e2e386ebf298547ca3a3704b729471f7ec666c2906c5c26c1a915ea24741ec"}, - {file = "jiter-0.11.1-cp313-cp313t-win_arm64.whl", hash = "sha256:fe4a431c291157e11cee7c34627990ea75e8d153894365a3bc84b7a959d23ca8"}, - {file = "jiter-0.11.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:0fa1f70da7a8a9713ff8e5f75ec3f90c0c870be6d526aa95e7c906f6a1c8c676"}, - {file = "jiter-0.11.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:569ee559e5046a42feb6828c55307cf20fe43308e3ae0d8e9e4f8d8634d99944"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f69955fa1d92e81987f092b233f0be49d4c937da107b7f7dcf56306f1d3fcce9"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:090f4c9d4a825e0fcbd0a2647c9a88a0f366b75654d982d95a9590745ff0c48d"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbf3d8cedf9e9d825233e0dcac28ff15c47b7c5512fdfe2e25fd5bbb6e6b0cee"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2aa9b1958f9c30d3d1a558b75f0626733c60eb9b7774a86b34d88060be1e67fe"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e42d1ca16590b768c5e7d723055acd2633908baacb3628dd430842e2e035aa90"}, - {file = "jiter-0.11.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5db4c2486a023820b701a17aec9c5a6173c5ba4393f26662f032f2de9c848b0f"}, - {file = "jiter-0.11.1-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:4573b78777ccfac954859a6eff45cbd9d281d80c8af049d0f1a3d9fc323d5c3a"}, - {file = "jiter-0.11.1-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:7593ac6f40831d7961cb67633c39b9fef6689a211d7919e958f45710504f52d3"}, - {file = "jiter-0.11.1-cp314-cp314-win32.whl", hash = "sha256:87202ec6ff9626ff5f9351507def98fcf0df60e9a146308e8ab221432228f4ea"}, - {file = "jiter-0.11.1-cp314-cp314-win_amd64.whl", hash = "sha256:a5dd268f6531a182c89d0dd9a3f8848e86e92dfff4201b77a18e6b98aa59798c"}, - {file = "jiter-0.11.1-cp314-cp314-win_arm64.whl", hash = "sha256:5d761f863f912a44748a21b5c4979c04252588ded8d1d2760976d2e42cd8d991"}, - {file = "jiter-0.11.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2cc5a3965285ddc33e0cab933e96b640bc9ba5940cea27ebbbf6695e72d6511c"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b572b3636a784c2768b2342f36a23078c8d3aa6d8a30745398b1bab58a6f1a8"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ad93e3d67a981f96596d65d2298fe8d1aa649deb5374a2fb6a434410ee11915e"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a83097ce379e202dcc3fe3fc71a16d523d1ee9192c8e4e854158f96b3efe3f2f"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7042c51e7fbeca65631eb0c332f90c0c082eab04334e7ccc28a8588e8e2804d9"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a68d679c0e47649a61df591660507608adc2652442de7ec8276538ac46abe08"}, - {file = "jiter-0.11.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1b0da75dbf4b6ec0b3c9e604d1ee8beaf15bc046fff7180f7d89e3cdbd3bb51"}, - {file = "jiter-0.11.1-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:69dd514bf0fa31c62147d6002e5ca2b3e7ef5894f5ac6f0a19752385f4e89437"}, - {file = "jiter-0.11.1-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:bb31ac0b339efa24c0ca606febd8b77ef11c58d09af1b5f2be4c99e907b11111"}, - {file = "jiter-0.11.1-cp314-cp314t-win32.whl", hash = "sha256:b2ce0d6156a1d3ad41da3eec63b17e03e296b78b0e0da660876fccfada86d2f7"}, - {file = "jiter-0.11.1-cp314-cp314t-win_amd64.whl", hash = "sha256:f4db07d127b54c4a2d43b4cf05ff0193e4f73e0dd90c74037e16df0b29f666e1"}, - {file = "jiter-0.11.1-cp314-cp314t-win_arm64.whl", hash = "sha256:28e4fdf2d7ebfc935523e50d1efa3970043cfaa161674fe66f9642409d001dfe"}, - {file = "jiter-0.11.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:baa99c8db49467527658bb479857344daf0a14dff909b7f6714579ac439d1253"}, - {file = "jiter-0.11.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:860fe55fa3b01ad0edf2adde1098247ff5c303d0121f9ce028c03d4f88c69502"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:173dd349d99b6feaf5a25a6fbcaf3489a6f947708d808240587a23df711c67db"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:14ac1dca837514cc946a6ac2c4995d9695303ecc754af70a3163d057d1a444ab"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69af47de5f93a231d5b85f7372d3284a5be8edb4cc758f006ec5a1406965ac5e"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:685f8b3abd3bbd3e06e4dfe2429ff87fd5d7a782701151af99b1fcbd80e31b2b"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d04afa2d4e5526e54ae8a58feea953b1844bf6e3526bc589f9de68e86d0ea01"}, - {file = "jiter-0.11.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1e92b927259035b50d8e11a8fdfe0ebd014d883e4552d37881643fa289a4bcf1"}, - {file = "jiter-0.11.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e7bd8be4fad8d4c5558b7801770cd2da6c072919c6f247cc5336edb143f25304"}, - {file = "jiter-0.11.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:121381a77a3c85987f3eba0d30ceaca9116f7463bedeec2fa79b2e7286b89b60"}, - {file = "jiter-0.11.1-cp39-cp39-win32.whl", hash = "sha256:160225407f6dfabdf9be1b44e22f06bc293a78a28ffa4347054698bd712dad06"}, - {file = "jiter-0.11.1-cp39-cp39-win_amd64.whl", hash = "sha256:028e0d59bcdfa1079f8df886cdaefc6f515c27a5288dec956999260c7e4a7cfd"}, - {file = "jiter-0.11.1-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:e642b5270e61dd02265866398707f90e365b5db2eb65a4f30c789d826682e1f6"}, - {file = "jiter-0.11.1-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:464ba6d000585e4e2fd1e891f31f1231f497273414f5019e27c00a4b8f7a24ad"}, - {file = "jiter-0.11.1-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:055568693ab35e0bf3a171b03bb40b2dcb10352359e0ab9b5ed0da2bf1eb6f6f"}, - {file = "jiter-0.11.1-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0c69ea798d08a915ba4478113efa9e694971e410056392f4526d796f136d3fa"}, - {file = "jiter-0.11.1-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:0d4d6993edc83cf75e8c6828a8d6ce40a09ee87e38c7bfba6924f39e1337e21d"}, - {file = "jiter-0.11.1-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f78d151c83a87a6cf5461d5ee55bc730dd9ae227377ac6f115b922989b95f838"}, - {file = "jiter-0.11.1-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9022974781155cd5521d5cb10997a03ee5e31e8454c9d999dcdccd253f2353f"}, - {file = "jiter-0.11.1-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18c77aaa9117510d5bdc6a946baf21b1f0cfa58ef04d31c8d016f206f2118960"}, - {file = "jiter-0.11.1.tar.gz", hash = "sha256:849dcfc76481c0ea0099391235b7ca97d7279e0fa4c86005457ac7c88e8b76dc"}, +files = [ + {file = "jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65"}, + {file = "jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74"}, + {file = "jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2"}, + {file = "jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025"}, + {file = "jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca"}, + {file = "jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4"}, + {file = "jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11"}, + {file = "jiter-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d8f8a7e317190b2c2d60eb2e8aa835270b008139562d70fe732e1c0020ec53c9"}, + {file = "jiter-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2218228a077e784c6c8f1a8e5d6b8cb1dea62ce25811c356364848554b2056cd"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9354ccaa2982bf2188fd5f57f79f800ef622ec67beb8329903abf6b10da7d423"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f2607185ea89b4af9a604d4c7ec40e45d3ad03ee66998b031134bc510232bb7"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a585a5e42d25f2e71db5f10b171f5e5ea641d3aa44f7df745aa965606111cc2"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd9e21d34edff5a663c631f850edcb786719c960ce887a5661e9c828a53a95d9"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a612534770470686cd5431478dc5a1b660eceb410abade6b1b74e320ca98de6"}, + {file = "jiter-0.12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3985aea37d40a908f887b34d05111e0aae822943796ebf8338877fee2ab67725"}, + {file = "jiter-0.12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b1207af186495f48f72529f8d86671903c8c10127cac6381b11dddc4aaa52df6"}, + {file = "jiter-0.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ef2fb241de583934c9915a33120ecc06d94aa3381a134570f59eed784e87001e"}, + {file = "jiter-0.12.0-cp311-cp311-win32.whl", hash = "sha256:453b6035672fecce8007465896a25b28a6b59cfe8fbc974b2563a92f5a92a67c"}, + {file = "jiter-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:ca264b9603973c2ad9435c71a8ec8b49f8f715ab5ba421c85a51cde9887e421f"}, + {file = "jiter-0.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:cb00ef392e7d684f2754598c02c409f376ddcef857aae796d559e6cacc2d78a5"}, + {file = "jiter-0.12.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:305e061fa82f4680607a775b2e8e0bcb071cd2205ac38e6ef48c8dd5ebe1cf37"}, + {file = "jiter-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c1860627048e302a528333c9307c818c547f214d8659b0705d2195e1a94b274"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df37577a4f8408f7e0ec3205d2a8f87672af8f17008358063a4d6425b6081ce3"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75fdd787356c1c13a4f40b43c2156276ef7a71eb487d98472476476d803fb2cf"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1eb5db8d9c65b112aacf14fcd0faae9913d07a8afea5ed06ccdd12b724e966a1"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73c568cc27c473f82480abc15d1301adf333a7ea4f2e813d6a2c7d8b6ba8d0df"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4321e8a3d868919bcb1abb1db550d41f2b5b326f72df29e53b2df8b006eb9403"}, + {file = "jiter-0.12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a51bad79f8cc9cac2b4b705039f814049142e0050f30d91695a2d9a6611f126"}, + {file = "jiter-0.12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2a67b678f6a5f1dd6c36d642d7db83e456bc8b104788262aaefc11a22339f5a9"}, + {file = "jiter-0.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efe1a211fe1fd14762adea941e3cfd6c611a136e28da6c39272dbb7a1bbe6a86"}, + {file = "jiter-0.12.0-cp312-cp312-win32.whl", hash = "sha256:d779d97c834b4278276ec703dc3fc1735fca50af63eb7262f05bdb4e62203d44"}, + {file = "jiter-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:e8269062060212b373316fe69236096aaf4c49022d267c6736eebd66bbbc60bb"}, + {file = "jiter-0.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:06cb970936c65de926d648af0ed3d21857f026b1cf5525cb2947aa5e01e05789"}, + {file = "jiter-0.12.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6cc49d5130a14b732e0612bc76ae8db3b49898732223ef8b7599aa8d9810683e"}, + {file = "jiter-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:37f27a32ce36364d2fa4f7fdc507279db604d27d239ea2e044c8f148410defe1"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbc0944aa3d4b4773e348cda635252824a78f4ba44328e042ef1ff3f6080d1cf"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da25c62d4ee1ffbacb97fac6dfe4dcd6759ebdc9015991e92a6eae5816287f44"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:048485c654b838140b007390b8182ba9774621103bd4d77c9c3f6f117474ba45"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:635e737fbb7315bef0037c19b88b799143d2d7d3507e61a76751025226b3ac87"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e017c417b1ebda911bd13b1e40612704b1f5420e30695112efdbed8a4b389ed"}, + {file = "jiter-0.12.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:89b0bfb8b2bf2351fba36bb211ef8bfceba73ef58e7f0c68fb67b5a2795ca2f9"}, + {file = "jiter-0.12.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:f5aa5427a629a824a543672778c9ce0c5e556550d1569bb6ea28a85015287626"}, + {file = "jiter-0.12.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed53b3d6acbcb0fd0b90f20c7cb3b24c357fe82a3518934d4edfa8c6898e498c"}, + {file = "jiter-0.12.0-cp313-cp313-win32.whl", hash = "sha256:4747de73d6b8c78f2e253a2787930f4fffc68da7fa319739f57437f95963c4de"}, + {file = "jiter-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:e25012eb0c456fcc13354255d0338cd5397cce26c77b2832b3c4e2e255ea5d9a"}, + {file = "jiter-0.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:c97b92c54fe6110138c872add030a1f99aea2401ddcdaa21edf74705a646dd60"}, + {file = "jiter-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:53839b35a38f56b8be26a7851a48b89bc47e5d88e900929df10ed93b95fea3d6"}, + {file = "jiter-0.12.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94f669548e55c91ab47fef8bddd9c954dab1938644e715ea49d7e117015110a4"}, + {file = "jiter-0.12.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:351d54f2b09a41600ffea43d081522d792e81dcfb915f6d2d242744c1cc48beb"}, + {file = "jiter-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2a5e90604620f94bf62264e7c2c038704d38217b7465b863896c6d7c902b06c7"}, + {file = "jiter-0.12.0-cp313-cp313t-win_arm64.whl", hash = "sha256:88ef757017e78d2860f96250f9393b7b577b06a956ad102c29c8237554380db3"}, + {file = "jiter-0.12.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c46d927acd09c67a9fb1416df45c5a04c27e83aae969267e98fba35b74e99525"}, + {file = "jiter-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:774ff60b27a84a85b27b88cd5583899c59940bcc126caca97eb2a9df6aa00c49"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5433fab222fb072237df3f637d01b81f040a07dcac1cb4a5c75c7aa9ed0bef1"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8c593c6e71c07866ec6bfb790e202a833eeec885022296aff6b9e0b92d6a70e"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90d32894d4c6877a87ae00c6b915b609406819dce8bc0d4e962e4de2784e567e"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:798e46eed9eb10c3adbbacbd3bdb5ecd4cf7064e453d00dbef08802dae6937ff"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3f1368f0a6719ea80013a4eb90ba72e75d7ea67cfc7846db2ca504f3df0169a"}, + {file = "jiter-0.12.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65f04a9d0b4406f7e51279710b27484af411896246200e461d80d3ba0caa901a"}, + {file = "jiter-0.12.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:fd990541982a24281d12b67a335e44f117e4c6cbad3c3b75c7dea68bf4ce3a67"}, + {file = "jiter-0.12.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:b111b0e9152fa7df870ecaebb0bd30240d9f7fff1f2003bcb4ed0f519941820b"}, + {file = "jiter-0.12.0-cp314-cp314-win32.whl", hash = "sha256:a78befb9cc0a45b5a5a0d537b06f8544c2ebb60d19d02c41ff15da28a9e22d42"}, + {file = "jiter-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:e1fe01c082f6aafbe5c8faf0ff074f38dfb911d53f07ec333ca03f8f6226debf"}, + {file = "jiter-0.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:d72f3b5a432a4c546ea4bedc84cce0c3404874f1d1676260b9c7f048a9855451"}, + {file = "jiter-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e6ded41aeba3603f9728ed2b6196e4df875348ab97b28fc8afff115ed42ba7a7"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a947920902420a6ada6ad51892082521978e9dd44a802663b001436e4b771684"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:add5e227e0554d3a52cf390a7635edaffdf4f8fce4fdbcef3cc2055bb396a30c"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9b1cda8fcb736250d7e8711d4580ebf004a46771432be0ae4796944b5dfa5d"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deeb12a2223fe0135c7ff1356a143d57f95bbf1f4a66584f1fc74df21d86b993"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c596cc0f4cb574877550ce4ecd51f8037469146addd676d7c1a30ebe6391923f"}, + {file = "jiter-0.12.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ab4c823b216a4aeab3fdbf579c5843165756bd9ad87cc6b1c65919c4715f783"}, + {file = "jiter-0.12.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:e427eee51149edf962203ff8db75a7514ab89be5cb623fb9cea1f20b54f1107b"}, + {file = "jiter-0.12.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:edb868841f84c111255ba5e80339d386d937ec1fdce419518ce1bd9370fac5b6"}, + {file = "jiter-0.12.0-cp314-cp314t-win32.whl", hash = "sha256:8bbcfe2791dfdb7c5e48baf646d37a6a3dcb5a97a032017741dea9f817dca183"}, + {file = "jiter-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2fa940963bf02e1d8226027ef461e36af472dea85d36054ff835aeed944dd873"}, + {file = "jiter-0.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:506c9708dd29b27288f9f8f1140c3cb0e3d8ddb045956d7757b1fa0e0f39a473"}, + {file = "jiter-0.12.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c9d28b218d5f9e5f69a0787a196322a5056540cb378cac8ff542b4fa7219966c"}, + {file = "jiter-0.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d0ee12028daf8cfcf880dd492349a122a64f42c059b6c62a2b0c96a83a8da820"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b135ebe757a82d67ed2821526e72d0acf87dd61f6013e20d3c45b8048af927b"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:15d7fafb81af8a9e3039fc305529a61cd933eecee33b4251878a1c89859552a3"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92d1f41211d8a8fe412faad962d424d334764c01dac6691c44691c2e4d3eedaf"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a64a48d7c917b8f32f25c176df8749ecf08cec17c466114727efe7441e17f6d"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:122046f3b3710b85de99d9aa2f3f0492a8233a2f54a64902b096efc27ea747b5"}, + {file = "jiter-0.12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:27ec39225e03c32c6b863ba879deb427882f243ae46f0d82d68b695fa5b48b40"}, + {file = "jiter-0.12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26b9e155ddc132225a39b1995b3b9f0fe0f79a6d5cbbeacf103271e7d309b404"}, + {file = "jiter-0.12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9ab05b7c58e29bb9e60b70c2e0094c98df79a1e42e397b9bb6eaa989b7a66dd0"}, + {file = "jiter-0.12.0-cp39-cp39-win32.whl", hash = "sha256:59f9f9df87ed499136db1c2b6c9efb902f964bed42a582ab7af413b6a293e7b0"}, + {file = "jiter-0.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:d3719596a1ebe7a48a498e8d5d0c4bf7553321d4c3eee1d620628d51351a3928"}, + {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:4739a4657179ebf08f85914ce50332495811004cc1747852e8b2041ed2aab9b8"}, + {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:41da8def934bf7bec16cb24bd33c0ca62126d2d45d81d17b864bd5ad721393c3"}, + {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c44ee814f499c082e69872d426b624987dbc5943ab06e9bbaa4f81989fdb79e"}, + {file = "jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2097de91cf03eaa27b3cbdb969addf83f0179c6afc41bbc4513705e013c65d"}, + {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:e8547883d7b96ef2e5fe22b88f8a4c8725a56e7f4abafff20fd5272d634c7ecb"}, + {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:89163163c0934854a668ed783a2546a0617f71706a2551a4a0666d91ab365d6b"}, + {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d96b264ab7d34bbb2312dedc47ce07cd53f06835eacbc16dde3761f47c3a9e7f"}, + {file = "jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c"}, + {file = "jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b"}, ] [[package]] @@ -615,7 +585,6 @@ version = "1.33" description = "Apply JSON-Patches (RFC 6902)" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" -groups = ["dev"] files = [ {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, @@ -630,7 +599,6 @@ version = "3.0.0" description = "Identify specific nodes in a JSON document (RFC 6901)" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"}, {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, @@ -642,7 +610,6 @@ version = "4.25.1" description = "An implementation of JSON Schema validation for Python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63"}, {file = "jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85"}, @@ -664,7 +631,6 @@ version = "2025.9.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe"}, {file = "jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d"}, @@ -675,24 +641,24 @@ referencing = ">=0.31.0" [[package]] name = "langchain" -version = "1.0.1" +version = "1.2.0" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0.0,>=3.10.0" -groups = ["dev"] files = [ - {file = "langchain-1.0.1-py3-none-any.whl", hash = "sha256:48fd616413fee4843f12cad49e8b74ad6fc159640142ca885d03bd925cd24503"}, - {file = "langchain-1.0.1.tar.gz", hash = "sha256:8bf60e096ca9c06626d9161a46651405ef1d12b5863f7679283666f83f760dc5"}, + {file = "langchain-1.2.0-py3-none-any.whl", hash = "sha256:82f0d17aa4fbb11560b30e1e7d4aeb75e3ad71ce09b85c90ab208b181a24ffac"}, + {file = "langchain-1.2.0.tar.gz", hash = "sha256:a087d1e2b2969819e29a91a6d5f98302aafe31bd49ba377ecee3bf5a5dcfe14a"}, ] [package.dependencies] -langchain-core = ">=1.0.0,<2.0.0" -langgraph = ">=1.0.0,<1.1.0" +langchain-core = ">=1.2.1,<2.0.0" +langgraph = ">=1.0.2,<1.1.0" pydantic = ">=2.7.4,<3.0.0" [package.extras] anthropic = ["langchain-anthropic"] aws = ["langchain-aws"] +azure-ai = ["langchain-azure-ai"] community = ["langchain-community"] deepseek = ["langchain-deepseek"] fireworks = ["langchain-fireworks"] @@ -709,14 +675,13 @@ xai = ["langchain-xai"] [[package]] name = "langchain-core" -version = "1.0.7" +version = "1.2.2" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0.0,>=3.10.0" -groups = ["dev"] files = [ - {file = "langchain_core-1.0.7-py3-none-any.whl", hash = "sha256:76af258b0e95a7915b8e301706a45ded50c75b80ff35329394d4df964416e32a"}, - {file = "langchain_core-1.0.7.tar.gz", hash = "sha256:6c64399cb0f163a7e45a764cce75d80fd08b82f4e0274ca892cfbcaa2f29200b"}, + {file = "langchain_core-1.2.2-py3-none-any.whl", hash = "sha256:3a83dc14217de5cba11b1a0bd43c48702401bbd18dc25cac2ffab5ac83a61cd0"}, + {file = "langchain_core-1.2.2.tar.gz", hash = "sha256:3f9c28ec6d0fe47636d28b19799794458d55da81f37309832b2b9d11c93c5e95"}, ] [package.dependencies] @@ -727,6 +692,7 @@ pydantic = ">=2.7.4,<3.0.0" pyyaml = ">=5.3.0,<7.0.0" tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10.0.0" typing-extensions = ">=4.7.0,<5.0.0" +uuid-utils = ">=0.12.0,<1.0" [[package]] name = "langchain-openai" @@ -734,7 +700,6 @@ version = "0.3.34" description = "An integration package connecting OpenAI and LangChain" optional = false python-versions = "<4.0.0,>=3.9.0" -groups = ["dev"] files = [ {file = "langchain_openai-0.3.34-py3-none-any.whl", hash = "sha256:08d61d68a6d869c70d542171e149b9065668dedfc4fafcd4de8aeb5b933030a9"}, {file = "langchain_openai-0.3.34.tar.gz", hash = "sha256:57916d462be5b8fd19e5cb2f00d4e5cf0465266a292d583de2fc693a55ba190e"}, @@ -747,50 +712,47 @@ tiktoken = ">=0.7.0,<1.0.0" [[package]] name = "langgraph" -version = "1.0.2" +version = "1.0.5" description = "Building stateful, multi-actor applications with LLMs" optional = false python-versions = ">=3.10" -groups = ["dev"] files = [ - {file = "langgraph-1.0.2-py3-none-any.whl", hash = "sha256:b3d56b8c01de857b5fb1da107e8eab6e30512a377685eeedb4f76456724c9729"}, - {file = "langgraph-1.0.2.tar.gz", hash = "sha256:dae1af08d6025cb1fcaed68f502c01af7d634d9044787c853a46c791cfc52f67"}, + {file = "langgraph-1.0.5-py3-none-any.whl", hash = "sha256:b4cfd173dca3c389735b47228ad8b295e6f7b3df779aba3a1e0c23871f81281e"}, + {file = "langgraph-1.0.5.tar.gz", hash = "sha256:7f6ae59622386b60fe9fa0ad4c53f42016b668455ed604329e7dc7904adbf3f8"}, ] [package.dependencies] langchain-core = ">=0.1" langgraph-checkpoint = ">=2.1.0,<4.0.0" langgraph-prebuilt = ">=1.0.2,<1.1.0" -langgraph-sdk = ">=0.2.2,<0.3.0" +langgraph-sdk = ">=0.3.0,<0.4.0" pydantic = ">=2.7.4" xxhash = ">=3.5.0" [[package]] name = "langgraph-checkpoint" -version = "3.0.0" +version = "3.0.1" description = "Library with base interfaces for LangGraph checkpoint savers." optional = false python-versions = ">=3.10" -groups = ["dev"] files = [ - {file = "langgraph_checkpoint-3.0.0-py3-none-any.whl", hash = "sha256:560beb83e629784ab689212a3d60834fb3196b4bbe1d6ac18e5cad5d85d46010"}, - {file = "langgraph_checkpoint-3.0.0.tar.gz", hash = "sha256:f738695ad938878d8f4775d907d9629e9fcd345b1950196effb08f088c52369e"}, + {file = "langgraph_checkpoint-3.0.1-py3-none-any.whl", hash = "sha256:9b04a8d0edc0474ce4eaf30c5d731cee38f11ddff50a6177eead95b5c4e4220b"}, + {file = "langgraph_checkpoint-3.0.1.tar.gz", hash = "sha256:59222f875f85186a22c494aedc65c4e985a3df27e696e5016ba0b98a5ed2cee0"}, ] [package.dependencies] langchain-core = ">=0.2.38" -ormsgpack = ">=1.10.0" +ormsgpack = ">=1.12.0" [[package]] name = "langgraph-prebuilt" -version = "1.0.2" +version = "1.0.5" description = "Library with high-level APIs for creating and executing LangGraph agents and tools." optional = false python-versions = ">=3.10" -groups = ["dev"] files = [ - {file = "langgraph_prebuilt-1.0.2-py3-none-any.whl", hash = "sha256:d9499f7c449fb637ee7b87e3f6a3b74095f4202053c74d33894bd839ea4c57c7"}, - {file = "langgraph_prebuilt-1.0.2.tar.gz", hash = "sha256:9896dbabf04f086eb59df4294f54ab5bdb21cd78e27e0a10e695dffd1cc6097d"}, + {file = "langgraph_prebuilt-1.0.5-py3-none-any.whl", hash = "sha256:22369563e1848862ace53fbc11b027c28dd04a9ac39314633bb95f2a7e258496"}, + {file = "langgraph_prebuilt-1.0.5.tar.gz", hash = "sha256:85802675ad778cc7240fd02d47db1e0b59c0c86d8369447d77ce47623845db2d"}, ] [package.dependencies] @@ -799,14 +761,13 @@ langgraph-checkpoint = ">=2.1.0,<4.0.0" [[package]] name = "langgraph-sdk" -version = "0.2.9" +version = "0.3.0" description = "SDK for interacting with LangGraph API" optional = false -python-versions = ">=3.9" -groups = ["dev"] +python-versions = ">=3.10" files = [ - {file = "langgraph_sdk-0.2.9-py3-none-any.whl", hash = "sha256:fbf302edadbf0fb343596f91c597794e936ef68eebc0d3e1d358b6f9f72a1429"}, - {file = "langgraph_sdk-0.2.9.tar.gz", hash = "sha256:b3bd04c6be4fa382996cd2be8fbc1e7cc94857d2bc6b6f4599a7f2a245975303"}, + {file = "langgraph_sdk-0.3.0-py3-none-any.whl", hash = "sha256:c1ade483fba17ae354ee920e4779042b18d5aba875f2a858ba569f62f628f26f"}, + {file = "langgraph_sdk-0.3.0.tar.gz", hash = "sha256:4145bc3c34feae227ae918341f66d3ba7d1499722c1ef4a8aae5ea828897d1d4"}, ] [package.dependencies] @@ -815,14 +776,13 @@ orjson = ">=3.10.1" [[package]] name = "langsmith" -version = "0.4.37" -description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." +version = "0.5.0" +description = "Client library to connect to the LangSmith Observability and Evaluation Platform." optional = false -python-versions = ">=3.9" -groups = ["dev"] +python-versions = ">=3.10" files = [ - {file = "langsmith-0.4.37-py3-none-any.whl", hash = "sha256:e34a94ce7277646299e4703a0f6e2d2c43647a28e8b800bb7ef82fd87a0ec766"}, - {file = "langsmith-0.4.37.tar.gz", hash = "sha256:d9a0eb6dd93f89843ac982c9f92be93cf2bcabbe19957f362c547766c7366c71"}, + {file = "langsmith-0.5.0-py3-none-any.whl", hash = "sha256:a83750cb3dccb33148d4ffe005e3e03080fad13e01671efbb74c9a68813bfef8"}, + {file = "langsmith-0.5.0.tar.gz", hash = "sha256:5cadf1ddd30e838cf61679f4a776aaef638d4b02ffbceba9f73283caebd39e1b"}, ] [package.dependencies] @@ -832,23 +792,108 @@ packaging = ">=23.2" pydantic = ">=1,<3" requests = ">=2.0.0" requests-toolbelt = ">=1.0.0" +uuid-utils = ">=0.12.0,<1.0" zstandard = ">=0.23.0" [package.extras] -claude-agent-sdk = ["claude-agent-sdk (>=0.1.0) ; python_version >= \"3.10\""] +claude-agent-sdk = ["claude-agent-sdk (>=0.1.0)"] langsmith-pyo3 = ["langsmith-pyo3 (>=0.1.0rc2)"] openai-agents = ["openai-agents (>=0.0.3)"] otel = ["opentelemetry-api (>=1.30.0)", "opentelemetry-exporter-otlp-proto-http (>=1.30.0)", "opentelemetry-sdk (>=1.30.0)"] pytest = ["pytest (>=7.0.0)", "rich (>=13.9.4)", "vcrpy (>=7.0.0)"] vcr = ["vcrpy (>=7.0.0)"] +[[package]] +name = "librt" +version = "0.7.4" +description = "Mypyc runtime library" +optional = false +python-versions = ">=3.9" +files = [ + {file = "librt-0.7.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dc300cb5a5a01947b1ee8099233156fdccd5001739e5f596ecfbc0dab07b5a3b"}, + {file = "librt-0.7.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee8d3323d921e0f6919918a97f9b5445a7dfe647270b2629ec1008aa676c0bc0"}, + {file = "librt-0.7.4-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:95cb80854a355b284c55f79674f6187cc9574df4dc362524e0cce98c89ee8331"}, + {file = "librt-0.7.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ca1caedf8331d8ad6027f93b52d68ed8f8009f5c420c246a46fe9d3be06be0f"}, + {file = "librt-0.7.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2a6f1236151e6fe1da289351b5b5bce49651c91554ecc7b70a947bced6fe212"}, + {file = "librt-0.7.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7766b57aeebaf3f1dac14fdd4a75c9a61f2ed56d8ebeefe4189db1cb9d2a3783"}, + {file = "librt-0.7.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1c4c89fb01157dd0a3bfe9e75cd6253b0a1678922befcd664eca0772a4c6c979"}, + {file = "librt-0.7.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f7fa8beef580091c02b4fd26542de046b2abfe0aaefa02e8bcf68acb7618f2b3"}, + {file = "librt-0.7.4-cp310-cp310-win32.whl", hash = "sha256:543c42fa242faae0466fe72d297976f3c710a357a219b1efde3a0539a68a6997"}, + {file = "librt-0.7.4-cp310-cp310-win_amd64.whl", hash = "sha256:25cc40d8eb63f0a7ea4c8f49f524989b9df901969cb860a2bc0e4bad4b8cb8a8"}, + {file = "librt-0.7.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3485b9bb7dfa66167d5500ffdafdc35415b45f0da06c75eb7df131f3357b174a"}, + {file = "librt-0.7.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:188b4b1a770f7f95ea035d5bbb9d7367248fc9d12321deef78a269ebf46a5729"}, + {file = "librt-0.7.4-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1b668b1c840183e4e38ed5a99f62fac44c3a3eef16870f7f17cfdfb8b47550ed"}, + {file = "librt-0.7.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0e8f864b521f6cfedb314d171630f827efee08f5c3462bcbc2244ab8e1768cd6"}, + {file = "librt-0.7.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4df7c9def4fc619a9c2ab402d73a0c5b53899abe090e0100323b13ccb5a3dd82"}, + {file = "librt-0.7.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f79bc3595b6ed159a1bf0cdc70ed6ebec393a874565cab7088a219cca14da727"}, + {file = "librt-0.7.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77772a4b8b5f77d47d883846928c36d730b6e612a6388c74cba33ad9eb149c11"}, + {file = "librt-0.7.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:064a286e6ab0b4c900e228ab4fa9cb3811b4b83d3e0cc5cd816b2d0f548cb61c"}, + {file = "librt-0.7.4-cp311-cp311-win32.whl", hash = "sha256:42da201c47c77b6cc91fc17e0e2b330154428d35d6024f3278aa2683e7e2daf2"}, + {file = "librt-0.7.4-cp311-cp311-win_amd64.whl", hash = "sha256:d31acb5886c16ae1711741f22504195af46edec8315fe69b77e477682a87a83e"}, + {file = "librt-0.7.4-cp311-cp311-win_arm64.whl", hash = "sha256:114722f35093da080a333b3834fff04ef43147577ed99dd4db574b03a5f7d170"}, + {file = "librt-0.7.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7dd3b5c37e0fb6666c27cf4e2c88ae43da904f2155c4cfc1e5a2fdce3b9fcf92"}, + {file = "librt-0.7.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9c5de1928c486201b23ed0cc4ac92e6e07be5cd7f3abc57c88a9cf4f0f32108"}, + {file = "librt-0.7.4-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:078ae52ffb3f036396cc4aed558e5b61faedd504a3c1f62b8ae34bf95ae39d94"}, + {file = "librt-0.7.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce58420e25097b2fc201aef9b9f6d65df1eb8438e51154e1a7feb8847e4a55ab"}, + {file = "librt-0.7.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b719c8730c02a606dc0e8413287e8e94ac2d32a51153b300baf1f62347858fba"}, + {file = "librt-0.7.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3749ef74c170809e6dee68addec9d2458700a8de703de081c888e92a8b015cf9"}, + {file = "librt-0.7.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b35c63f557653c05b5b1b6559a074dbabe0afee28ee2a05b6c9ba21ad0d16a74"}, + {file = "librt-0.7.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1ef704e01cb6ad39ad7af668d51677557ca7e5d377663286f0ee1b6b27c28e5f"}, + {file = "librt-0.7.4-cp312-cp312-win32.whl", hash = "sha256:c66c2b245926ec15188aead25d395091cb5c9df008d3b3207268cd65557d6286"}, + {file = "librt-0.7.4-cp312-cp312-win_amd64.whl", hash = "sha256:71a56f4671f7ff723451f26a6131754d7c1809e04e22ebfbac1db8c9e6767a20"}, + {file = "librt-0.7.4-cp312-cp312-win_arm64.whl", hash = "sha256:419eea245e7ec0fe664eb7e85e7ff97dcdb2513ca4f6b45a8ec4a3346904f95a"}, + {file = "librt-0.7.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d44a1b1ba44cbd2fc3cb77992bef6d6fdb1028849824e1dd5e4d746e1f7f7f0b"}, + {file = "librt-0.7.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c9cab4b3de1f55e6c30a84c8cee20e4d3b2476f4d547256694a1b0163da4fe32"}, + {file = "librt-0.7.4-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2857c875f1edd1feef3c371fbf830a61b632fb4d1e57160bb1e6a3206e6abe67"}, + {file = "librt-0.7.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b370a77be0a16e1ad0270822c12c21462dc40496e891d3b0caf1617c8cc57e20"}, + {file = "librt-0.7.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d05acd46b9a52087bfc50c59dfdf96a2c480a601e8898a44821c7fd676598f74"}, + {file = "librt-0.7.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:70969229cb23d9c1a80e14225838d56e464dc71fa34c8342c954fc50e7516dee"}, + {file = "librt-0.7.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4450c354b89dbb266730893862dbff06006c9ed5b06b6016d529b2bf644fc681"}, + {file = "librt-0.7.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:adefe0d48ad35b90b6f361f6ff5a1bd95af80c17d18619c093c60a20e7a5b60c"}, + {file = "librt-0.7.4-cp313-cp313-win32.whl", hash = "sha256:21ea710e96c1e050635700695095962a22ea420d4b3755a25e4909f2172b4ff2"}, + {file = "librt-0.7.4-cp313-cp313-win_amd64.whl", hash = "sha256:772e18696cf5a64afee908662fbcb1f907460ddc851336ee3a848ef7684c8e1e"}, + {file = "librt-0.7.4-cp313-cp313-win_arm64.whl", hash = "sha256:52e34c6af84e12921748c8354aa6acf1912ca98ba60cdaa6920e34793f1a0788"}, + {file = "librt-0.7.4-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4f1ee004942eaaed6e06c087d93ebc1c67e9a293e5f6b9b5da558df6bf23dc5d"}, + {file = "librt-0.7.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d854c6dc0f689bad7ed452d2a3ecff58029d80612d336a45b62c35e917f42d23"}, + {file = "librt-0.7.4-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a4f7339d9e445280f23d63dea842c0c77379c4a47471c538fc8feedab9d8d063"}, + {file = "librt-0.7.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39003fc73f925e684f8521b2dbf34f61a5deb8a20a15dcf53e0d823190ce8848"}, + {file = "librt-0.7.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6bb15ee29d95875ad697d449fe6071b67f730f15a6961913a2b0205015ca0843"}, + {file = "librt-0.7.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:02a69369862099e37d00765583052a99d6a68af7e19b887e1b78fee0146b755a"}, + {file = "librt-0.7.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ec72342cc4d62f38b25a94e28b9efefce41839aecdecf5e9627473ed04b7be16"}, + {file = "librt-0.7.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:776dbb9bfa0fc5ce64234b446995d8d9f04badf64f544ca036bd6cff6f0732ce"}, + {file = "librt-0.7.4-cp314-cp314-win32.whl", hash = "sha256:0f8cac84196d0ffcadf8469d9ded4d4e3a8b1c666095c2a291e22bf58e1e8a9f"}, + {file = "librt-0.7.4-cp314-cp314-win_amd64.whl", hash = "sha256:037f5cb6fe5abe23f1dc058054d50e9699fcc90d0677eee4e4f74a8677636a1a"}, + {file = "librt-0.7.4-cp314-cp314-win_arm64.whl", hash = "sha256:a5deebb53d7a4d7e2e758a96befcd8edaaca0633ae71857995a0f16033289e44"}, + {file = "librt-0.7.4-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b4c25312c7f4e6ab35ab16211bdf819e6e4eddcba3b2ea632fb51c9a2a97e105"}, + {file = "librt-0.7.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:618b7459bb392bdf373f2327e477597fff8f9e6a1878fffc1b711c013d1b0da4"}, + {file = "librt-0.7.4-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1437c3f72a30c7047f16fd3e972ea58b90172c3c6ca309645c1c68984f05526a"}, + {file = "librt-0.7.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c96cb76f055b33308f6858b9b594618f1b46e147a4d03a4d7f0c449e304b9b95"}, + {file = "librt-0.7.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28f990e6821204f516d09dc39966ef8b84556ffd648d5926c9a3f681e8de8906"}, + {file = "librt-0.7.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc4aebecc79781a1b77d7d4e7d9fe080385a439e198d993b557b60f9117addaf"}, + {file = "librt-0.7.4-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:022cc673e69283a42621dd453e2407cf1647e77f8bd857d7ad7499901e62376f"}, + {file = "librt-0.7.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2b3ca211ae8ea540569e9c513da052699b7b06928dcda61247cb4f318122bdb5"}, + {file = "librt-0.7.4-cp314-cp314t-win32.whl", hash = "sha256:8a461f6456981d8c8e971ff5a55f2e34f4e60871e665d2f5fde23ee74dea4eeb"}, + {file = "librt-0.7.4-cp314-cp314t-win_amd64.whl", hash = "sha256:721a7b125a817d60bf4924e1eec2a7867bfcf64cfc333045de1df7a0629e4481"}, + {file = "librt-0.7.4-cp314-cp314t-win_arm64.whl", hash = "sha256:76b2ba71265c0102d11458879b4d53ccd0b32b0164d14deb8d2b598a018e502f"}, + {file = "librt-0.7.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6fc4aa67fedd827a601f97f0e61cc72711d0a9165f2c518e9a7c38fc1568b9ad"}, + {file = "librt-0.7.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e710c983d29d9cc4da29113b323647db286eaf384746344f4a233708cca1a82c"}, + {file = "librt-0.7.4-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:43a2515a33f2bc17b15f7fb49ff6426e49cb1d5b2539bc7f8126b9c5c7f37164"}, + {file = "librt-0.7.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fd766bb9ace3498f6b93d32f30c0e7c8ce6b727fecbc84d28160e217bb66254"}, + {file = "librt-0.7.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ce1b44091355b68cffd16e2abac07c1cafa953fa935852d3a4dd8975044ca3bf"}, + {file = "librt-0.7.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5a72b905420c4bb2c10c87b5c09fe6faf4a76d64730e3802feef255e43dfbf5a"}, + {file = "librt-0.7.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:07c4d7c9305e75a0edd3427b79c7bd1d019cd7eddaa7c89dbb10e0c7946bffbb"}, + {file = "librt-0.7.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2e734c2c54423c6dcc77f58a8585ba83b9f72e422f9edf09cab1096d4a4bdc82"}, + {file = "librt-0.7.4-cp39-cp39-win32.whl", hash = "sha256:a34ae11315d4e26326aaf04e21ccd8d9b7de983635fba38d73e203a9c8e3fe3d"}, + {file = "librt-0.7.4-cp39-cp39-win_amd64.whl", hash = "sha256:7e4b5ffa1614ad4f32237d739699be444be28de95071bfa4e66a8da9fa777798"}, + {file = "librt-0.7.4.tar.gz", hash = "sha256:3871af56c59864d5fd21d1ac001eb2fb3b140d52ba0454720f2e4a19812404ba"}, +] + [[package]] name = "markupsafe" version = "3.0.3" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" -groups = ["dev", "docs"] files = [ {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, @@ -943,53 +988,53 @@ files = [ [[package]] name = "mypy" -version = "1.18.2" +version = "1.19.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c"}, - {file = "mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e"}, - {file = "mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b"}, - {file = "mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66"}, - {file = "mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428"}, - {file = "mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed"}, - {file = "mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f"}, - {file = "mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341"}, - {file = "mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d"}, - {file = "mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86"}, - {file = "mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37"}, - {file = "mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8"}, - {file = "mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34"}, - {file = "mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764"}, - {file = "mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893"}, - {file = "mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914"}, - {file = "mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8"}, - {file = "mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074"}, - {file = "mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc"}, - {file = "mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e"}, - {file = "mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986"}, - {file = "mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d"}, - {file = "mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba"}, - {file = "mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544"}, - {file = "mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce"}, - {file = "mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d"}, - {file = "mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c"}, - {file = "mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb"}, - {file = "mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075"}, - {file = "mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf"}, - {file = "mypy-1.18.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25a9c8fb67b00599f839cf472713f54249a62efd53a54b565eb61956a7e3296b"}, - {file = "mypy-1.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2b9c7e284ee20e7598d6f42e13ca40b4928e6957ed6813d1ab6348aa3f47133"}, - {file = "mypy-1.18.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6985ed057513e344e43a26cc1cd815c7a94602fb6a3130a34798625bc2f07b6"}, - {file = "mypy-1.18.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f27105f1525ec024b5c630c0b9f36d5c1cc4d447d61fe51ff4bd60633f47ac"}, - {file = "mypy-1.18.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:030c52d0ea8144e721e49b1f68391e39553d7451f0c3f8a7565b59e19fcb608b"}, - {file = "mypy-1.18.2-cp39-cp39-win_amd64.whl", hash = "sha256:aa5e07ac1a60a253445797e42b8b2963c9675563a94f11291ab40718b016a7a0"}, - {file = "mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e"}, - {file = "mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b"}, +files = [ + {file = "mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec"}, + {file = "mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b"}, + {file = "mypy-1.19.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee4c11e460685c3e0c64a4c5de82ae143622410950d6be863303a1c4ba0e36d6"}, + {file = "mypy-1.19.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de759aafbae8763283b2ee5869c7255391fbc4de3ff171f8f030b5ec48381b74"}, + {file = "mypy-1.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ab43590f9cd5108f41aacf9fca31841142c786827a74ab7cc8a2eacb634e09a1"}, + {file = "mypy-1.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:2899753e2f61e571b3971747e302d5f420c3fd09650e1951e99f823bc3089dac"}, + {file = "mypy-1.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288"}, + {file = "mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab"}, + {file = "mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6"}, + {file = "mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331"}, + {file = "mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925"}, + {file = "mypy-1.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042"}, + {file = "mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1"}, + {file = "mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e"}, + {file = "mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2"}, + {file = "mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8"}, + {file = "mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a"}, + {file = "mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13"}, + {file = "mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250"}, + {file = "mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b"}, + {file = "mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e"}, + {file = "mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef"}, + {file = "mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75"}, + {file = "mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd"}, + {file = "mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1"}, + {file = "mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718"}, + {file = "mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b"}, + {file = "mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045"}, + {file = "mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957"}, + {file = "mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f"}, + {file = "mypy-1.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7bcfc336a03a1aaa26dfce9fff3e287a3ba99872a157561cbfcebe67c13308e3"}, + {file = "mypy-1.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b7951a701c07ea584c4fe327834b92a30825514c868b1f69c30445093fdd9d5a"}, + {file = "mypy-1.19.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b13cfdd6c87fc3efb69ea4ec18ef79c74c3f98b4e5498ca9b85ab3b2c2329a67"}, + {file = "mypy-1.19.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f28f99c824ecebcdaa2e55d82953e38ff60ee5ec938476796636b86afa3956e"}, + {file = "mypy-1.19.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c608937067d2fc5a4dd1a5ce92fd9e1398691b8c5d012d66e1ddd430e9244376"}, + {file = "mypy-1.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:409088884802d511ee52ca067707b90c883426bd95514e8cfda8281dc2effe24"}, + {file = "mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247"}, + {file = "mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba"}, ] [package.dependencies] +librt = {version = ">=0.6.2", markers = "platform_python_implementation != \"PyPy\""} mypy_extensions = ">=1.0.0" pathspec = ">=0.9.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} @@ -1008,7 +1053,6 @@ version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, @@ -1020,7 +1064,6 @@ version = "1.9.1" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["dev"] files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, @@ -1028,14 +1071,13 @@ files = [ [[package]] name = "openai" -version = "2.5.0" +version = "2.13.0" description = "The official Python library for the openai API" optional = false -python-versions = ">=3.8" -groups = ["main", "dev"] +python-versions = ">=3.9" files = [ - {file = "openai-2.5.0-py3-none-any.whl", hash = "sha256:21380e5f52a71666dbadbf322dd518bdf2b9d11ed0bb3f96bea17310302d6280"}, - {file = "openai-2.5.0.tar.gz", hash = "sha256:f8fa7611f96886a0f31ac6b97e58bc0ada494b255ee2cfd51c8eb502cfcb4814"}, + {file = "openai-2.13.0-py3-none-any.whl", hash = "sha256:746521065fed68df2f9c2d85613bb50844343ea81f60009b60e6a600c9352c79"}, + {file = "openai-2.13.0.tar.gz", hash = "sha256:9ff633b07a19469ec476b1e2b5b26c5ef700886524a7a72f65e6f0b5203142d5"}, ] [package.dependencies] @@ -1060,7 +1102,6 @@ version = "1.38.0" description = "OpenTelemetry Python API" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "opentelemetry_api-1.38.0-py3-none-any.whl", hash = "sha256:2891b0197f47124454ab9f0cf58f3be33faca394457ac3e09daba13ff50aa582"}, {file = "opentelemetry_api-1.38.0.tar.gz", hash = "sha256:f4c193b5e8acb0912b06ac5b16321908dd0843d75049c091487322284a3eea12"}, @@ -1076,7 +1117,6 @@ version = "1.38.0" description = "OpenTelemetry Protobuf encoding" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "opentelemetry_exporter_otlp_proto_common-1.38.0-py3-none-any.whl", hash = "sha256:03cb76ab213300fe4f4c62b7d8f17d97fcfd21b89f0b5ce38ea156327ddda74a"}, {file = "opentelemetry_exporter_otlp_proto_common-1.38.0.tar.gz", hash = "sha256:e333278afab4695aa8114eeb7bf4e44e65c6607d54968271a249c180b2cb605c"}, @@ -1091,7 +1131,6 @@ version = "1.38.0" description = "OpenTelemetry Collector Protobuf over HTTP Exporter" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "opentelemetry_exporter_otlp_proto_http-1.38.0-py3-none-any.whl", hash = "sha256:84b937305edfc563f08ec69b9cb2298be8188371217e867c1854d77198d0825b"}, {file = "opentelemetry_exporter_otlp_proto_http-1.38.0.tar.gz", hash = "sha256:f16bd44baf15cbe07633c5112ffc68229d0edbeac7b37610be0b2def4e21e90b"}, @@ -1112,7 +1151,6 @@ version = "0.59b0" description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "opentelemetry_instrumentation-0.59b0-py3-none-any.whl", hash = "sha256:44082cc8fe56b0186e87ee8f7c17c327c4c2ce93bdbe86496e600985d74368ee"}, {file = "opentelemetry_instrumentation-0.59b0.tar.gz", hash = "sha256:6010f0faaacdaf7c4dff8aac84e226d23437b331dcda7e70367f6d73a7db1adc"}, @@ -1130,7 +1168,6 @@ version = "0.59b0" description = "Thread context propagation support for OpenTelemetry" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "opentelemetry_instrumentation_threading-0.59b0-py3-none-any.whl", hash = "sha256:76da2fc01fe1dccebff6581080cff9e42ac7b27cc61eb563f3c4435c727e8eca"}, {file = "opentelemetry_instrumentation_threading-0.59b0.tar.gz", hash = "sha256:ce5658730b697dcbc0e0d6d13643a69fd8aeb1b32fa8db3bade8ce114c7975f3"}, @@ -1147,7 +1184,6 @@ version = "1.38.0" description = "OpenTelemetry Python Proto" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "opentelemetry_proto-1.38.0-py3-none-any.whl", hash = "sha256:b6ebe54d3217c42e45462e2a1ae28c3e2bf2ec5a5645236a490f55f45f1a0a18"}, {file = "opentelemetry_proto-1.38.0.tar.gz", hash = "sha256:88b161e89d9d372ce723da289b7da74c3a8354a8e5359992be813942969ed468"}, @@ -1162,7 +1198,6 @@ version = "1.38.0" description = "OpenTelemetry Python SDK" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ {file = "opentelemetry_sdk-1.38.0-py3-none-any.whl", hash = "sha256:1c66af6564ecc1553d72d811a01df063ff097cdc82ce188da9951f93b8d10f6b"}, {file = "opentelemetry_sdk-1.38.0.tar.gz", hash = "sha256:93df5d4d871ed09cb4272305be4d996236eedb232253e3ab864c8620f051cebe"}, @@ -1179,7 +1214,6 @@ version = "0.59b0" description = "OpenTelemetry Semantic Conventions" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "opentelemetry_semantic_conventions-0.59b0-py3-none-any.whl", hash = "sha256:35d3b8833ef97d614136e253c1da9342b4c3c083bbaf29ce31d572a1c3825eed"}, {file = "opentelemetry_semantic_conventions-0.59b0.tar.gz", hash = "sha256:7a6db3f30d70202d5bf9fa4b69bc866ca6a30437287de6c510fb594878aed6b0"}, @@ -1191,161 +1225,155 @@ typing-extensions = ">=4.5.0" [[package]] name = "orjson" -version = "3.11.3" +version = "3.11.5" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "orjson-3.11.3-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:29cb1f1b008d936803e2da3d7cba726fc47232c45df531b29edf0b232dd737e7"}, - {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97dceed87ed9139884a55db8722428e27bd8452817fbf1869c58b49fecab1120"}, - {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58533f9e8266cb0ac298e259ed7b4d42ed3fa0b78ce76860626164de49e0d467"}, - {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c212cfdd90512fe722fa9bd620de4d46cda691415be86b2e02243242ae81873"}, - {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff835b5d3e67d9207343effb03760c00335f8b5285bfceefd4dc967b0e48f6a"}, - {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5aa4682912a450c2db89cbd92d356fef47e115dffba07992555542f344d301b"}, - {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7d18dd34ea2e860553a579df02041845dee0af8985dff7f8661306f95504ddf"}, - {file = "orjson-3.11.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d8b11701bc43be92ea42bd454910437b355dfb63696c06fe953ffb40b5f763b4"}, - {file = "orjson-3.11.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:90368277087d4af32d38bd55f9da2ff466d25325bf6167c8f382d8ee40cb2bbc"}, - {file = "orjson-3.11.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fd7ff459fb393358d3a155d25b275c60b07a2c83dcd7ea962b1923f5a1134569"}, - {file = "orjson-3.11.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f8d902867b699bcd09c176a280b1acdab57f924489033e53d0afe79817da37e6"}, - {file = "orjson-3.11.3-cp310-cp310-win32.whl", hash = "sha256:bb93562146120bb51e6b154962d3dadc678ed0fce96513fa6bc06599bb6f6edc"}, - {file = "orjson-3.11.3-cp310-cp310-win_amd64.whl", hash = "sha256:976c6f1975032cc327161c65d4194c549f2589d88b105a5e3499429a54479770"}, - {file = "orjson-3.11.3-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9d2ae0cc6aeb669633e0124531f342a17d8e97ea999e42f12a5ad4adaa304c5f"}, - {file = "orjson-3.11.3-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:ba21dbb2493e9c653eaffdc38819b004b7b1b246fb77bfc93dc016fe664eac91"}, - {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00f1a271e56d511d1569937c0447d7dce5a99a33ea0dec76673706360a051904"}, - {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b67e71e47caa6680d1b6f075a396d04fa6ca8ca09aafb428731da9b3ea32a5a6"}, - {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d7d012ebddffcce8c85734a6d9e5f08180cd3857c5f5a3ac70185b43775d043d"}, - {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd759f75d6b8d1b62012b7f5ef9461d03c804f94d539a5515b454ba3a6588038"}, - {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6890ace0809627b0dff19cfad92d69d0fa3f089d3e359a2a532507bb6ba34efb"}, - {file = "orjson-3.11.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9d4a5e041ae435b815e568537755773d05dac031fee6a57b4ba70897a44d9d2"}, - {file = "orjson-3.11.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d68bf97a771836687107abfca089743885fb664b90138d8761cce61d5625d55"}, - {file = "orjson-3.11.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bfc27516ec46f4520b18ef645864cee168d2a027dbf32c5537cb1f3e3c22dac1"}, - {file = "orjson-3.11.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f66b001332a017d7945e177e282a40b6997056394e3ed7ddb41fb1813b83e824"}, - {file = "orjson-3.11.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:212e67806525d2561efbfe9e799633b17eb668b8964abed6b5319b2f1cfbae1f"}, - {file = "orjson-3.11.3-cp311-cp311-win32.whl", hash = "sha256:6e8e0c3b85575a32f2ffa59de455f85ce002b8bdc0662d6b9c2ed6d80ab5d204"}, - {file = "orjson-3.11.3-cp311-cp311-win_amd64.whl", hash = "sha256:6be2f1b5d3dc99a5ce5ce162fc741c22ba9f3443d3dd586e6a1211b7bc87bc7b"}, - {file = "orjson-3.11.3-cp311-cp311-win_arm64.whl", hash = "sha256:fafb1a99d740523d964b15c8db4eabbfc86ff29f84898262bf6e3e4c9e97e43e"}, - {file = "orjson-3.11.3-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8c752089db84333e36d754c4baf19c0e1437012242048439c7e80eb0e6426e3b"}, - {file = "orjson-3.11.3-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:9b8761b6cf04a856eb544acdd82fc594b978f12ac3602d6374a7edb9d86fd2c2"}, - {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b13974dc8ac6ba22feaa867fc19135a3e01a134b4f7c9c28162fed4d615008a"}, - {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f83abab5bacb76d9c821fd5c07728ff224ed0e52d7a71b7b3de822f3df04e15c"}, - {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e6fbaf48a744b94091a56c62897b27c31ee2da93d826aa5b207131a1e13d4064"}, - {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc779b4f4bba2847d0d2940081a7b6f7b5877e05408ffbb74fa1faf4a136c424"}, - {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd4b909ce4c50faa2192da6bb684d9848d4510b736b0611b6ab4020ea6fd2d23"}, - {file = "orjson-3.11.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:524b765ad888dc5518bbce12c77c2e83dee1ed6b0992c1790cc5fb49bb4b6667"}, - {file = "orjson-3.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:84fd82870b97ae3cdcea9d8746e592b6d40e1e4d4527835fc520c588d2ded04f"}, - {file = "orjson-3.11.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fbecb9709111be913ae6879b07bafd4b0785b44c1eb5cac8ac76da048b3885a1"}, - {file = "orjson-3.11.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9dba358d55aee552bd868de348f4736ca5a4086d9a62e2bfbbeeb5629fe8b0cc"}, - {file = "orjson-3.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eabcf2e84f1d7105f84580e03012270c7e97ecb1fb1618bda395061b2a84a049"}, - {file = "orjson-3.11.3-cp312-cp312-win32.whl", hash = "sha256:3782d2c60b8116772aea8d9b7905221437fdf53e7277282e8d8b07c220f96cca"}, - {file = "orjson-3.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:79b44319268af2eaa3e315b92298de9a0067ade6e6003ddaef72f8e0bedb94f1"}, - {file = "orjson-3.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:0e92a4e83341ef79d835ca21b8bd13e27c859e4e9e4d7b63defc6e58462a3710"}, - {file = "orjson-3.11.3-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:af40c6612fd2a4b00de648aa26d18186cd1322330bd3a3cc52f87c699e995810"}, - {file = "orjson-3.11.3-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:9f1587f26c235894c09e8b5b7636a38091a9e6e7fe4531937534749c04face43"}, - {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61dcdad16da5bb486d7227a37a2e789c429397793a6955227cedbd7252eb5a27"}, - {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11c6d71478e2cbea0a709e8a06365fa63da81da6498a53e4c4f065881d21ae8f"}, - {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff94112e0098470b665cb0ed06efb187154b63649403b8d5e9aedeb482b4548c"}, - {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae8b756575aaa2a855a75192f356bbda11a89169830e1439cfb1a3e1a6dde7be"}, - {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9416cc19a349c167ef76135b2fe40d03cea93680428efee8771f3e9fb66079d"}, - {file = "orjson-3.11.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b822caf5b9752bc6f246eb08124c3d12bf2175b66ab74bac2ef3bbf9221ce1b2"}, - {file = "orjson-3.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:414f71e3bdd5573893bf5ecdf35c32b213ed20aa15536fe2f588f946c318824f"}, - {file = "orjson-3.11.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:828e3149ad8815dc14468f36ab2a4b819237c155ee1370341b91ea4c8672d2ee"}, - {file = "orjson-3.11.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac9e05f25627ffc714c21f8dfe3a579445a5c392a9c8ae7ba1d0e9fb5333f56e"}, - {file = "orjson-3.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e44fbe4000bd321d9f3b648ae46e0196d21577cf66ae684a96ff90b1f7c93633"}, - {file = "orjson-3.11.3-cp313-cp313-win32.whl", hash = "sha256:2039b7847ba3eec1f5886e75e6763a16e18c68a63efc4b029ddf994821e2e66b"}, - {file = "orjson-3.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:29be5ac4164aa8bdcba5fa0700a3c9c316b411d8ed9d39ef8a882541bd452fae"}, - {file = "orjson-3.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:18bd1435cb1f2857ceb59cfb7de6f92593ef7b831ccd1b9bfb28ca530e539dce"}, - {file = "orjson-3.11.3-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:cf4b81227ec86935568c7edd78352a92e97af8da7bd70bdfdaa0d2e0011a1ab4"}, - {file = "orjson-3.11.3-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:bc8bc85b81b6ac9fc4dae393a8c159b817f4c2c9dee5d12b773bddb3b95fc07e"}, - {file = "orjson-3.11.3-cp314-cp314-manylinux_2_34_aarch64.whl", hash = "sha256:88dcfc514cfd1b0de038443c7b3e6a9797ffb1b3674ef1fd14f701a13397f82d"}, - {file = "orjson-3.11.3-cp314-cp314-manylinux_2_34_x86_64.whl", hash = "sha256:d61cd543d69715d5fc0a690c7c6f8dcc307bc23abef9738957981885f5f38229"}, - {file = "orjson-3.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2b7b153ed90ababadbef5c3eb39549f9476890d339cf47af563aea7e07db2451"}, - {file = "orjson-3.11.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:7909ae2460f5f494fecbcd10613beafe40381fd0316e35d6acb5f3a05bfda167"}, - {file = "orjson-3.11.3-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:2030c01cbf77bc67bee7eef1e7e31ecf28649353987775e3583062c752da0077"}, - {file = "orjson-3.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a0169ebd1cbd94b26c7a7ad282cf5c2744fce054133f959e02eb5265deae1872"}, - {file = "orjson-3.11.3-cp314-cp314-win32.whl", hash = "sha256:0c6d7328c200c349e3a4c6d8c83e0a5ad029bdc2d417f234152bf34842d0fc8d"}, - {file = "orjson-3.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:317bbe2c069bbc757b1a2e4105b64aacd3bc78279b66a6b9e51e846e4809f804"}, - {file = "orjson-3.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:e8f6a7a27d7b7bec81bd5924163e9af03d49bbb63013f107b48eb5d16db711bc"}, - {file = "orjson-3.11.3-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:56afaf1e9b02302ba636151cfc49929c1bb66b98794291afd0e5f20fecaf757c"}, - {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:913f629adef31d2d350d41c051ce7e33cf0fd06a5d1cb28d49b1899b23b903aa"}, - {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0a23b41f8f98b4e61150a03f83e4f0d566880fe53519d445a962929a4d21045"}, - {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3d721fee37380a44f9d9ce6c701b3960239f4fb3d5ceea7f31cbd43882edaa2f"}, - {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73b92a5b69f31b1a58c0c7e31080aeaec49c6e01b9522e71ff38d08f15aa56de"}, - {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2489b241c19582b3f1430cc5d732caefc1aaf378d97e7fb95b9e56bed11725f"}, - {file = "orjson-3.11.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5189a5dab8b0312eadaf9d58d3049b6a52c454256493a557405e77a3d67ab7f"}, - {file = "orjson-3.11.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9d8787bdfbb65a85ea76d0e96a3b1bed7bf0fbcb16d40408dc1172ad784a49d2"}, - {file = "orjson-3.11.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:8e531abd745f51f8035e207e75e049553a86823d189a51809c078412cefb399a"}, - {file = "orjson-3.11.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8ab962931015f170b97a3dd7bd933399c1bae8ed8ad0fb2a7151a5654b6941c7"}, - {file = "orjson-3.11.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:124d5ba71fee9c9902c4a7baa9425e663f7f0aecf73d31d54fe3dd357d62c1a7"}, - {file = "orjson-3.11.3-cp39-cp39-win32.whl", hash = "sha256:22724d80ee5a815a44fc76274bb7ba2e7464f5564aacb6ecddaa9970a83e3225"}, - {file = "orjson-3.11.3-cp39-cp39-win_amd64.whl", hash = "sha256:215c595c792a87d4407cb72dd5e0f6ee8e694ceeb7f9102b533c5a9bf2a916bb"}, - {file = "orjson-3.11.3.tar.gz", hash = "sha256:1c0603b1d2ffcd43a411d64797a19556ef76958aef1c182f22dc30860152a98a"}, +files = [ + {file = "orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e"}, + {file = "orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f"}, + {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18"}, + {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a"}, + {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7"}, + {file = "orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401"}, + {file = "orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8"}, + {file = "orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167"}, + {file = "orjson-3.11.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9c8494625ad60a923af6b2b0bd74107146efe9b55099e20d7740d995f338fcd8"}, + {file = "orjson-3.11.5-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:7bb2ce0b82bc9fd1168a513ddae7a857994b780b2945a8c51db4ab1c4b751ebc"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67394d3becd50b954c4ecd24ac90b5051ee7c903d167459f93e77fc6f5b4c968"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:298d2451f375e5f17b897794bcc3e7b821c0f32b4788b9bcae47ada24d7f3cf7"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa5e4244063db8e1d87e0f54c3f7522f14b2dc937e65d5241ef0076a096409fd"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1db2088b490761976c1b2e956d5d4e6409f3732e9d79cfa69f876c5248d1baf9"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2ed66358f32c24e10ceea518e16eb3549e34f33a9d51f99ce23b0251776a1ef"}, + {file = "orjson-3.11.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2021afda46c1ed64d74b555065dbd4c2558d510d8cec5ea6a53001b3e5e82a9"}, + {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b42ffbed9128e547a1647a3e50bc88ab28ae9daa61713962e0d3dd35e820c125"}, + {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8d5f16195bb671a5dd3d1dbea758918bada8f6cc27de72bd64adfbd748770814"}, + {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c0e5d9f7a0227df2927d343a6e3859bebf9208b427c79bd31949abcc2fa32fa5"}, + {file = "orjson-3.11.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:23d04c4543e78f724c4dfe656b3791b5f98e4c9253e13b2636f1af5d90e4a880"}, + {file = "orjson-3.11.5-cp311-cp311-win32.whl", hash = "sha256:c404603df4865f8e0afe981aa3c4b62b406e6d06049564d58934860b62b7f91d"}, + {file = "orjson-3.11.5-cp311-cp311-win_amd64.whl", hash = "sha256:9645ef655735a74da4990c24ffbd6894828fbfa117bc97c1edd98c282ecb52e1"}, + {file = "orjson-3.11.5-cp311-cp311-win_arm64.whl", hash = "sha256:1cbf2735722623fcdee8e712cbaaab9e372bbcb0c7924ad711b261c2eccf4a5c"}, + {file = "orjson-3.11.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:334e5b4bff9ad101237c2d799d9fd45737752929753bf4faf4b207335a416b7d"}, + {file = "orjson-3.11.5-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:ff770589960a86eae279f5d8aa536196ebda8273a2a07db2a54e82b93bc86626"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed24250e55efbcb0b35bed7caaec8cedf858ab2f9f2201f17b8938c618c8ca6f"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a66d7769e98a08a12a139049aac2f0ca3adae989817f8c43337455fbc7669b85"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:86cfc555bfd5794d24c6a1903e558b50644e5e68e6471d66502ce5cb5fdef3f9"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a230065027bc2a025e944f9d4714976a81e7ecfa940923283bca7bbc1f10f626"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b29d36b60e606df01959c4b982729c8845c69d1963f88686608be9ced96dbfaa"}, + {file = "orjson-3.11.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c74099c6b230d4261fdc3169d50efc09abf38ace1a42ea2f9994b1d79153d477"}, + {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e697d06ad57dd0c7a737771d470eedc18e68dfdefcdd3b7de7f33dfda5b6212e"}, + {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e08ca8a6c851e95aaecc32bc44a5aa75d0ad26af8cdac7c77e4ed93acf3d5b69"}, + {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e8b5f96c05fce7d0218df3fdfeb962d6b8cfff7e3e20264306b46dd8b217c0f3"}, + {file = "orjson-3.11.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ddbfdb5099b3e6ba6d6ea818f61997bb66de14b411357d24c4612cf1ebad08ca"}, + {file = "orjson-3.11.5-cp312-cp312-win32.whl", hash = "sha256:9172578c4eb09dbfcf1657d43198de59b6cef4054de385365060ed50c458ac98"}, + {file = "orjson-3.11.5-cp312-cp312-win_amd64.whl", hash = "sha256:2b91126e7b470ff2e75746f6f6ee32b9ab67b7a93c8ba1d15d3a0caaf16ec875"}, + {file = "orjson-3.11.5-cp312-cp312-win_arm64.whl", hash = "sha256:acbc5fac7e06777555b0722b8ad5f574739e99ffe99467ed63da98f97f9ca0fe"}, + {file = "orjson-3.11.5-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:3b01799262081a4c47c035dd77c1301d40f568f77cc7ec1bb7db5d63b0a01629"}, + {file = "orjson-3.11.5-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:61de247948108484779f57a9f406e4c84d636fa5a59e411e6352484985e8a7c3"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:894aea2e63d4f24a7f04a1908307c738d0dce992e9249e744b8f4e8dd9197f39"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ddc21521598dbe369d83d4d40338e23d4101dad21dae0e79fa20465dbace019f"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7cce16ae2f5fb2c53c3eafdd1706cb7b6530a67cc1c17abe8ec747f5cd7c0c51"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e46c762d9f0e1cfb4ccc8515de7f349abbc95b59cb5a2bd68df5973fdef913f8"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d7345c759276b798ccd6d77a87136029e71e66a8bbf2d2755cbdde1d82e78706"}, + {file = "orjson-3.11.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75bc2e59e6a2ac1dd28901d07115abdebc4563b5b07dd612bf64260a201b1c7f"}, + {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:54aae9b654554c3b4edd61896b978568c6daa16af96fa4681c9b5babd469f863"}, + {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:4bdd8d164a871c4ec773f9de0f6fe8769c2d6727879c37a9666ba4183b7f8228"}, + {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a261fef929bcf98a60713bf5e95ad067cea16ae345d9a35034e73c3990e927d2"}, + {file = "orjson-3.11.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c028a394c766693c5c9909dec76b24f37e6a1b91999e8d0c0d5feecbe93c3e05"}, + {file = "orjson-3.11.5-cp313-cp313-win32.whl", hash = "sha256:2cc79aaad1dfabe1bd2d50ee09814a1253164b3da4c00a78c458d82d04b3bdef"}, + {file = "orjson-3.11.5-cp313-cp313-win_amd64.whl", hash = "sha256:ff7877d376add4e16b274e35a3f58b7f37b362abf4aa31863dadacdd20e3a583"}, + {file = "orjson-3.11.5-cp313-cp313-win_arm64.whl", hash = "sha256:59ac72ea775c88b163ba8d21b0177628bd015c5dd060647bbab6e22da3aad287"}, + {file = "orjson-3.11.5-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e446a8ea0a4c366ceafc7d97067bfd55292969143b57e3c846d87fc701e797a0"}, + {file = "orjson-3.11.5-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:53deb5addae9c22bbe3739298f5f2196afa881ea75944e7720681c7080909a81"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82cd00d49d6063d2b8791da5d4f9d20539c5951f965e45ccf4e96d33505ce68f"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3fd15f9fc8c203aeceff4fda211157fad114dde66e92e24097b3647a08f4ee9e"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9df95000fbe6777bf9820ae82ab7578e8662051bb5f83d71a28992f539d2cda7"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a8d676748fca47ade5bc3da7430ed7767afe51b2f8100e3cd65e151c0eaceb"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa0f513be38b40234c77975e68805506cad5d57b3dfd8fe3baa7f4f4051e15b4"}, + {file = "orjson-3.11.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1863e75b92891f553b7922ce4ee10ed06db061e104f2b7815de80cdcb135ad"}, + {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4be86b58e9ea262617b8ca6251a2f0d63cc132a6da4b5fcc8e0a4128782c829"}, + {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:b923c1c13fa02084eb38c9c065afd860a5cff58026813319a06949c3af5732ac"}, + {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:1b6bd351202b2cd987f35a13b5e16471cf4d952b42a73c391cc537974c43ef6d"}, + {file = "orjson-3.11.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bb150d529637d541e6af06bbe3d02f5498d628b7f98267ff87647584293ab439"}, + {file = "orjson-3.11.5-cp314-cp314-win32.whl", hash = "sha256:9cc1e55c884921434a84a0c3dd2699eb9f92e7b441d7f53f3941079ec6ce7499"}, + {file = "orjson-3.11.5-cp314-cp314-win_amd64.whl", hash = "sha256:a4f3cb2d874e03bc7767c8f88adaa1a9a05cecea3712649c3b58589ec7317310"}, + {file = "orjson-3.11.5-cp314-cp314-win_arm64.whl", hash = "sha256:38b22f476c351f9a1c43e5b07d8b5a02eb24a6ab8e75f700f7d479d4568346a5"}, + {file = "orjson-3.11.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1b280e2d2d284a6713b0cfec7b08918ebe57df23e3f76b27586197afca3cb1e9"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c8d8a112b274fae8c5f0f01954cb0480137072c271f3f4958127b010dfefaec"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0a2ae6f09ac7bd47d2d5a5305c1d9ed08ac057cda55bb0a49fa506f0d2da00"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0d87bd1896faac0d10b4f849016db81a63e4ec5df38757ffae84d45ab38aa71"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:801a821e8e6099b8c459ac7540b3c32dba6013437c57fdcaec205b169754f38c"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:69a0f6ac618c98c74b7fbc8c0172ba86f9e01dbf9f62aa0b1776c2231a7bffe5"}, + {file = "orjson-3.11.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fea7339bdd22e6f1060c55ac31b6a755d86a5b2ad3657f2669ec243f8e3b2bdb"}, + {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4dad582bc93cef8f26513e12771e76385a7e6187fd713157e971c784112aad56"}, + {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:0522003e9f7fba91982e83a97fec0708f5a714c96c4209db7104e6b9d132f111"}, + {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7403851e430a478440ecc1258bcbacbfbd8175f9ac1e39031a7121dd0de05ff8"}, + {file = "orjson-3.11.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5f691263425d3177977c8d1dd896cde7b98d93cbf390b2544a090675e83a6a0a"}, + {file = "orjson-3.11.5-cp39-cp39-win32.whl", hash = "sha256:61026196a1c4b968e1b1e540563e277843082e9e97d78afa03eb89315af531f1"}, + {file = "orjson-3.11.5-cp39-cp39-win_amd64.whl", hash = "sha256:09b94b947ac08586af635ef922d69dc9bc63321527a3a04647f4986a73f4bd30"}, + {file = "orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5"}, ] [[package]] name = "ormsgpack" -version = "1.11.0" -description = "" +version = "1.12.1" +description = "Fast, correct Python msgpack library supporting dataclasses, datetimes, and numpy" optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "ormsgpack-1.11.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:03d4e658dd6e1882a552ce1d13cc7b49157414e7d56a4091fbe7823225b08cba"}, - {file = "ormsgpack-1.11.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bb67eb913c2b703f0ed39607fc56e50724dd41f92ce080a586b4d6149eb3fe4"}, - {file = "ormsgpack-1.11.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e54175b92411f73a238e5653a998627f6660de3def37d9dd7213e0fd264ca56"}, - {file = "ormsgpack-1.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca2b197f4556e1823d1319869d4c5dc278be335286d2308b0ed88b59a5afcc25"}, - {file = "ormsgpack-1.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc62388262f58c792fe1e450e1d9dbcc174ed2fb0b43db1675dd7c5ff2319d6a"}, - {file = "ormsgpack-1.11.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c48bc10af74adfbc9113f3fb160dc07c61ad9239ef264c17e449eba3de343dc2"}, - {file = "ormsgpack-1.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a608d3a1d4fa4acdc5082168a54513cff91f47764cef435e81a483452f5f7647"}, - {file = "ormsgpack-1.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:97217b4f7f599ba45916b9c4c4b1d5656e8e2a4d91e2e191d72a7569d3c30923"}, - {file = "ormsgpack-1.11.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:c7be823f47d8e36648d4bc90634b93f02b7d7cc7480081195f34767e86f181fb"}, - {file = "ormsgpack-1.11.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68accf15d1b013812755c0eb7a30e1fc2f81eb603a1a143bf0cda1b301cfa797"}, - {file = "ormsgpack-1.11.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:805d06fb277d9a4e503c0c707545b49cde66cbb2f84e5cf7c58d81dfc20d8658"}, - {file = "ormsgpack-1.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1e57cdf003e77acc43643bda151dc01f97147a64b11cdee1380bb9698a7601c"}, - {file = "ormsgpack-1.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:37fc05bdaabd994097c62e2f3e08f66b03f856a640ede6dc5ea340bd15b77f4d"}, - {file = "ormsgpack-1.11.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a6e9db6c73eb46b2e4d97bdffd1368a66f54e6806b563a997b19c004ef165e1d"}, - {file = "ormsgpack-1.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e9c44eae5ac0196ffc8b5ed497c75511056508f2303fa4d36b208eb820cf209e"}, - {file = "ormsgpack-1.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:11d0dfaf40ae7c6de4f7dbd1e4892e2e6a55d911ab1774357c481158d17371e4"}, - {file = "ormsgpack-1.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:0c63a3f7199a3099c90398a1bdf0cb577b06651a442dc5efe67f2882665e5b02"}, - {file = "ormsgpack-1.11.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:3434d0c8d67de27d9010222de07fb6810fb9af3bb7372354ffa19257ac0eb83b"}, - {file = "ormsgpack-1.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2da5bd097e8dbfa4eb0d4ccfe79acd6f538dee4493579e2debfe4fc8f4ca89b"}, - {file = "ormsgpack-1.11.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fdbaa0a5a8606a486960b60c24f2d5235d30ac7a8b98eeaea9854bffef14dc3d"}, - {file = "ormsgpack-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3682f24f800c1837017ee90ce321086b2cbaef88db7d4cdbbda1582aa6508159"}, - {file = "ormsgpack-1.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:fcca21202bb05ccbf3e0e92f560ee59b9331182e4c09c965a28155efbb134993"}, - {file = "ormsgpack-1.11.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c30e5c4655ba46152d722ec7468e8302195e6db362ec1ae2c206bc64f6030e43"}, - {file = "ormsgpack-1.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7138a341f9e2c08c59368f03d3be25e8b87b3baaf10d30fb1f6f6b52f3d47944"}, - {file = "ormsgpack-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:d4bd8589b78a11026d47f4edf13c1ceab9088bb12451f34396afe6497db28a27"}, - {file = "ormsgpack-1.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:e5e746a1223e70f111d4001dab9585ac8639eee8979ca0c8db37f646bf2961da"}, - {file = "ormsgpack-1.11.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0e7b36ab7b45cb95217ae1f05f1318b14a3e5ef73cb00804c0f06233f81a14e8"}, - {file = "ormsgpack-1.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43402d67e03a9a35cc147c8c03f0c377cad016624479e1ee5b879b8425551484"}, - {file = "ormsgpack-1.11.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:64fd992f932764d6306b70ddc755c1bc3405c4c6a69f77a36acf7af1c8f5ada4"}, - {file = "ormsgpack-1.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0362fb7fe4a29c046c8ea799303079a09372653a1ce5a5a588f3bbb8088368d0"}, - {file = "ormsgpack-1.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:de2f7a65a9d178ed57be49eba3d0fc9b833c32beaa19dbd4ba56014d3c20b152"}, - {file = "ormsgpack-1.11.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f38cfae95461466055af966fc922d06db4e1654966385cda2828653096db34da"}, - {file = "ormsgpack-1.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c88396189d238f183cea7831b07a305ab5c90d6d29b53288ae11200bd956357b"}, - {file = "ormsgpack-1.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:5403d1a945dd7c81044cebeca3f00a28a0f4248b33242a5d2d82111628043725"}, - {file = "ormsgpack-1.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:c57357b8d43b49722b876edf317bdad9e6d52071b523fdd7394c30cd1c67d5a0"}, - {file = "ormsgpack-1.11.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:d390907d90fd0c908211592c485054d7a80990697ef4dff4e436ac18e1aab98a"}, - {file = "ormsgpack-1.11.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6153c2e92e789509098e04c9aa116b16673bd88ec78fbe0031deeb34ab642d10"}, - {file = "ormsgpack-1.11.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2b2c2a065a94d742212b2018e1fecd8f8d72f3c50b53a97d1f407418093446d"}, - {file = "ormsgpack-1.11.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:110e65b5340f3d7ef8b0009deae3c6b169437e6b43ad5a57fd1748085d29d2ac"}, - {file = "ormsgpack-1.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c27e186fca96ab34662723e65b420919910acbbc50fc8e1a44e08f26268cb0e0"}, - {file = "ormsgpack-1.11.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d56b1f877c13d499052d37a3db2378a97d5e1588d264f5040b3412aee23d742c"}, - {file = "ormsgpack-1.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c88e28cd567c0a3269f624b4ade28142d5e502c8e826115093c572007af5be0a"}, - {file = "ormsgpack-1.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:8811160573dc0a65f62f7e0792c4ca6b7108dfa50771edb93f9b84e2d45a08ae"}, - {file = "ormsgpack-1.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:23e30a8d3c17484cf74e75e6134322255bd08bc2b5b295cc9c442f4bae5f3c2d"}, - {file = "ormsgpack-1.11.0-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:2905816502adfaf8386a01dd85f936cd378d243f4f5ee2ff46f67f6298dc90d5"}, - {file = "ormsgpack-1.11.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c04402fb9a0a9b9f18fbafd6d5f8398ee99b3ec619fb63952d3a954bc9d47daa"}, - {file = "ormsgpack-1.11.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a025ec07ac52056ecfd9e57b5cbc6fff163f62cb9805012b56cda599157f8ef2"}, - {file = "ormsgpack-1.11.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:354c6a5039faf63b63d8f42ec7915583a4a56e10b319284370a5a89c4382d985"}, - {file = "ormsgpack-1.11.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7058c85cc13dd329bc7b528e38626c6babcd0066d6e9163330a1509fe0aa4707"}, - {file = "ormsgpack-1.11.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4e15b634be324fb18dab7aa82ab929a0d57d42c12650ae3dedd07d8d31b17733"}, - {file = "ormsgpack-1.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6329e6eae9dfe600962739a6e060ea82885ec58b8338875c5ac35080da970f94"}, - {file = "ormsgpack-1.11.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b27546c28f92b9eb757620f7f1ed89fb7b07be3b9f4ba1b7de75761ec1c4bcc8"}, - {file = "ormsgpack-1.11.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:26a17919d9144b4ac7112dbbadef07927abbe436be2cf99a703a19afe7dd5c8b"}, - {file = "ormsgpack-1.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5352868ee4cdc00656bf216b56bc654f72ac3008eb36e12561f6337bb7104b45"}, - {file = "ormsgpack-1.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:2ffe36f1f441a40949e8587f5aa3d3fc9f100576925aab667117403eab494338"}, - {file = "ormsgpack-1.11.0.tar.gz", hash = "sha256:7c9988e78fedba3292541eb3bb274fa63044ef4da2ddb47259ea70c05dee4206"}, +python-versions = ">=3.10" +files = [ + {file = "ormsgpack-1.12.1-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:62e3614cab63fa5aa42f5f0ca3cd12899f0bfc5eb8a5a0ebab09d571c89d427d"}, + {file = "ormsgpack-1.12.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86d9fbf85c05c69c33c229d2eba7c8c3500a56596cd8348131c918acd040d6af"}, + {file = "ormsgpack-1.12.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8d246e66f09d8e0f96e770829149ee83206e90ed12f5987998bb7be84aec99fe"}, + {file = "ormsgpack-1.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfc2c830a1ed2d00de713d08c9e62efa699e8fd29beafa626aaebe466f583ebb"}, + {file = "ormsgpack-1.12.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc892757d8f9eea5208268a527cf93c98409802f6a9f7c8d71a7b8f9ba5cb944"}, + {file = "ormsgpack-1.12.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0de1dbcf11ea739ac4a882b43d5c2055e6d99ce64e8d6502e25d6d881700c017"}, + {file = "ormsgpack-1.12.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d5065dfb9ec4db93241c60847624d9aeef4ccb449c26a018c216b55c69be83c0"}, + {file = "ormsgpack-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d17103c4726181d7000c61b751c881f1b6f401d146df12da028fc730227df19"}, + {file = "ormsgpack-1.12.1-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4038f59ae0e19dac5e5d9aae4ec17ff84a79e046342ee73ccdecf3547ecf0d34"}, + {file = "ormsgpack-1.12.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16c63b0c5a3eec467e4bb33a14dabba076b7d934dff62898297b5c0b5f7c3cb3"}, + {file = "ormsgpack-1.12.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:74fd6a8e037eb310dda865298e8d122540af00fe5658ec18b97a1d34f4012e4d"}, + {file = "ormsgpack-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58ad60308e233dd824a1859eabb5fe092e123e885eafa4ad5789322329c80fb5"}, + {file = "ormsgpack-1.12.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:35127464c941c1219acbe1a220e48d55e7933373d12257202f4042f7044b4c90"}, + {file = "ormsgpack-1.12.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c48d1c50794692d1e6e3f8c3bb65f5c3acfaae9347e506484a65d60b3d91fb50"}, + {file = "ormsgpack-1.12.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b512b2ad6feaaefdc26e05431ed2843e42483041e354e167c53401afaa83d919"}, + {file = "ormsgpack-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:93f30db95e101a9616323bfc50807ad00e7f6197cea2216d2d24af42afc77d88"}, + {file = "ormsgpack-1.12.1-cp311-cp311-win_arm64.whl", hash = "sha256:d75b5fa14f6abffce2c392ee03b4731199d8a964c81ee8645c4c79af0e80fd50"}, + {file = "ormsgpack-1.12.1-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4d7fb0e1b6fbc701d75269f7405a4f79230a6ce0063fb1092e4f6577e312f86d"}, + {file = "ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43a9353e2db5b024c91a47d864ef15eaa62d81824cfc7740fed4cef7db738694"}, + {file = "ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fc8fe866b7706fc25af0adf1f600bc06ece5b15ca44e34641327198b821e5c3c"}, + {file = "ormsgpack-1.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:813755b5f598a78242042e05dfd1ada4e769e94b98c9ab82554550f97ff4d641"}, + {file = "ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8eea2a13536fae45d78f93f2cc846c9765c7160c85f19cfefecc20873c137cdd"}, + {file = "ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7a02ebda1a863cbc604740e76faca8eee1add322db2dcbe6cf32669fffdff65c"}, + {file = "ormsgpack-1.12.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3c0bd63897c439931cdf29348e5e6e8c330d529830e848d10767615c0f3d1b82"}, + {file = "ormsgpack-1.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:362f2e812f8d7035dc25a009171e09d7cc97cb30d3c9e75a16aeae00ca3c1dcf"}, + {file = "ormsgpack-1.12.1-cp312-cp312-win_arm64.whl", hash = "sha256:6190281e381db2ed0045052208f47a995ccf61eed48f1215ae3cce3fbccd59c5"}, + {file = "ormsgpack-1.12.1-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:9663d6b3ecc917c063d61a99169ce196a80f3852e541ae404206836749459279"}, + {file = "ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32e85cfbaf01a94a92520e7fe7851cfcfe21a5698299c28ab86194895f9b9233"}, + {file = "ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dabfd2c24b59c7c69870a5ecee480dfae914a42a0c2e7c9d971cf531e2ba471a"}, + {file = "ormsgpack-1.12.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51bbf2b64afeded34ccd8e25402e4bca038757913931fa0d693078d75563f6f9"}, + {file = "ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9959a71dde1bd0ced84af17facc06a8afada495a34e9cb1bad8e9b20d4c59cef"}, + {file = "ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:e9be0e3b62d758f21f5b20e0e06b3a240ec546c4a327bf771f5825462aa74714"}, + {file = "ormsgpack-1.12.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a29d49ab7fdd77ea787818e60cb4ef491708105b9c4c9b0f919201625eb036b5"}, + {file = "ormsgpack-1.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:c418390b47a1d367e803f6c187f77e4d67c7ae07ba962e3a4a019001f4b0291a"}, + {file = "ormsgpack-1.12.1-cp313-cp313-win_arm64.whl", hash = "sha256:cfa22c91cffc10a7fbd43729baff2de7d9c28cef2509085a704168ae31f02568"}, + {file = "ormsgpack-1.12.1-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:b93c91efb1a70751a1902a5b43b27bd8fd38e0ca0365cf2cde2716423c15c3a6"}, + {file = "ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf0ea0389167b5fa8d2933dd3f33e887ec4ba68f89c25214d7eec4afd746d22"}, + {file = "ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f4c29af837f35af3375070689e781161e7cf019eb2f7cd641734ae45cd001c0d"}, + {file = "ormsgpack-1.12.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:336fc65aa0fe65896a3dabaae31e332a0a98b4a00ad7b0afde21a7505fd23ff3"}, + {file = "ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:940f60aabfefe71dd6b82cb33f4ff10b2e7f5fcfa5f103cdb0a23b6aae4c713c"}, + {file = "ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:596ad9e1b6d4c95595c54aaf49b1392609ca68f562ce06f4f74a5bc4053bcda4"}, + {file = "ormsgpack-1.12.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:575210e8fcbc7b0375026ba040a5eef223e9f66a4453d9623fc23282ae09c3c8"}, + {file = "ormsgpack-1.12.1-cp314-cp314-win_amd64.whl", hash = "sha256:647daa3718572280893456be44c60aea6690b7f2edc54c55648ee66e8f06550f"}, + {file = "ormsgpack-1.12.1-cp314-cp314-win_arm64.whl", hash = "sha256:a8b3ab762a6deaf1b6490ab46dda0c51528cf8037e0246c40875c6fe9e37b699"}, + {file = "ormsgpack-1.12.1-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:12087214e436c1f6c28491949571abea759a63111908c4f7266586d78144d7a8"}, + {file = "ormsgpack-1.12.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6d54c14cf86ef13f10ccade94d1e7de146aa9b17d371e18b16e95f329393b7"}, + {file = "ormsgpack-1.12.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f3584d07882b7ea2a1a589f795a3af97fe4c2932b739408e6d1d9d286cad862"}, + {file = "ormsgpack-1.12.1.tar.gz", hash = "sha256:a3877fde1e4f27a39f92681a0aab6385af3a41d0c25375d33590ae20410ea2ac"}, ] [[package]] @@ -1354,7 +1382,6 @@ version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, @@ -1366,7 +1393,6 @@ version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -1378,7 +1404,6 @@ version = "15.0.4" description = "API Documentation for Python Projects" optional = false python-versions = ">=3.9" -groups = ["docs"] files = [ {file = "pdoc-15.0.4-py3-none-any.whl", hash = "sha256:f9028e85e7bb8475b054e69bde1f6d26fc4693d25d9fa1b1ce9009bec7f7a5c4"}, {file = "pdoc-15.0.4.tar.gz", hash = "sha256:cf9680f10f5b4863381f44ef084b1903f8f356acb0d4cc6b64576ba9fb712c82"}, @@ -1391,14 +1416,13 @@ pygments = ">=2.12.0" [[package]] name = "platformdirs" -version = "4.5.0" +version = "4.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.10" -groups = ["dev"] files = [ - {file = "platformdirs-4.5.0-py3-none-any.whl", hash = "sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3"}, - {file = "platformdirs-4.5.0.tar.gz", hash = "sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312"}, + {file = "platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31"}, + {file = "platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda"}, ] [package.extras] @@ -1412,7 +1436,6 @@ version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, @@ -1428,7 +1451,6 @@ version = "0.9.0" description = "A fast C-implemented library for Levenshtein distance" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "polyleven-0.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6e00207fbe0fcdde206b9b277cf14bb9db8801f8d303204b1572870797399974"}, {file = "polyleven-0.9.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d400f255af038f77b37d5010532e0e82d07160457c8282e5b40632987ab815be"}, @@ -1493,7 +1515,6 @@ version = "3.8.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, @@ -1508,171 +1529,172 @@ virtualenv = ">=20.10.0" [[package]] name = "protobuf" -version = "6.33.0" +version = "6.33.2" description = "" optional = false python-versions = ">=3.9" -groups = ["main"] files = [ - {file = "protobuf-6.33.0-cp310-abi3-win32.whl", hash = "sha256:d6101ded078042a8f17959eccd9236fb7a9ca20d3b0098bbcb91533a5680d035"}, - {file = "protobuf-6.33.0-cp310-abi3-win_amd64.whl", hash = "sha256:9a031d10f703f03768f2743a1c403af050b6ae1f3480e9c140f39c45f81b13ee"}, - {file = "protobuf-6.33.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:905b07a65f1a4b72412314082c7dbfae91a9e8b68a0cc1577515f8df58ecf455"}, - {file = "protobuf-6.33.0-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e0697ece353e6239b90ee43a9231318302ad8353c70e6e45499fa52396debf90"}, - {file = "protobuf-6.33.0-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:e0a1715e4f27355afd9570f3ea369735afc853a6c3951a6afe1f80d8569ad298"}, - {file = "protobuf-6.33.0-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:35be49fd3f4fefa4e6e2aacc35e8b837d6703c37a2168a55ac21e9b1bc7559ef"}, - {file = "protobuf-6.33.0-cp39-cp39-win32.whl", hash = "sha256:cd33a8e38ea3e39df66e1bbc462b076d6e5ba3a4ebbde58219d777223a7873d3"}, - {file = "protobuf-6.33.0-cp39-cp39-win_amd64.whl", hash = "sha256:c963e86c3655af3a917962c9619e1a6b9670540351d7af9439d06064e3317cc9"}, - {file = "protobuf-6.33.0-py3-none-any.whl", hash = "sha256:25c9e1963c6734448ea2d308cfa610e692b801304ba0908d7bfa564ac5132995"}, - {file = "protobuf-6.33.0.tar.gz", hash = "sha256:140303d5c8d2037730c548f8c7b93b20bb1dc301be280c378b82b8894589c954"}, + {file = "protobuf-6.33.2-cp310-abi3-win32.whl", hash = "sha256:87eb388bd2d0f78febd8f4c8779c79247b26a5befad525008e49a6955787ff3d"}, + {file = "protobuf-6.33.2-cp310-abi3-win_amd64.whl", hash = "sha256:fc2a0e8b05b180e5fc0dd1559fe8ebdae21a27e81ac77728fb6c42b12c7419b4"}, + {file = "protobuf-6.33.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d9b19771ca75935b3a4422957bc518b0cecb978b31d1dd12037b088f6bcc0e43"}, + {file = "protobuf-6.33.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5d3b5625192214066d99b2b605f5783483575656784de223f00a8d00754fc0e"}, + {file = "protobuf-6.33.2-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8cd7640aee0b7828b6d03ae518b5b4806fdfc1afe8de82f79c3454f8aef29872"}, + {file = "protobuf-6.33.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:1f8017c48c07ec5859106533b682260ba3d7c5567b1ca1f24297ce03384d1b4f"}, + {file = "protobuf-6.33.2-cp39-cp39-win32.whl", hash = "sha256:7109dcc38a680d033ffb8bf896727423528db9163be1b6a02d6a49606dcadbfe"}, + {file = "protobuf-6.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:2981c58f582f44b6b13173e12bb8656711189c2a70250845f264b877f00b1913"}, + {file = "protobuf-6.33.2-py3-none-any.whl", hash = "sha256:7636aad9bb01768870266de5dc009de2d1b936771b38a793f73cbbf279c91c5c"}, + {file = "protobuf-6.33.2.tar.gz", hash = "sha256:56dc370c91fbb8ac85bc13582c9e373569668a290aa2e66a590c2a0d35ddb9e4"}, ] [[package]] name = "pydantic" -version = "2.12.3" +version = "2.12.5" description = "Data validation using Python type hints" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ - {file = "pydantic-2.12.3-py3-none-any.whl", hash = "sha256:6986454a854bc3bc6e5443e1369e06a3a456af9d339eda45510f517d9ea5c6bf"}, - {file = "pydantic-2.12.3.tar.gz", hash = "sha256:1da1c82b0fc140bb0103bc1441ffe062154c8d38491189751ee00fd8ca65ce74"}, + {file = "pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d"}, + {file = "pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.41.4" +pydantic-core = "2.41.5" typing-extensions = ">=4.14.1" typing-inspection = ">=0.4.2" [package.extras] email = ["email-validator (>=2.0.0)"] -timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] +timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.41.4" +version = "2.41.5" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] -files = [ - {file = "pydantic_core-2.41.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2442d9a4d38f3411f22eb9dd0912b7cbf4b7d5b6c92c4173b75d3e1ccd84e36e"}, - {file = "pydantic_core-2.41.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:30a9876226dda131a741afeab2702e2d127209bde3c65a2b8133f428bc5d006b"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d55bbac04711e2980645af68b97d445cdbcce70e5216de444a6c4b6943ebcccd"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e1d778fb7849a42d0ee5927ab0f7453bf9f85eef8887a546ec87db5ddb178945"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b65077a4693a98b90ec5ad8f203ad65802a1b9b6d4a7e48066925a7e1606706"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62637c769dee16eddb7686bf421be48dfc2fae93832c25e25bc7242e698361ba"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfe3aa529c8f501babf6e502936b9e8d4698502b2cfab41e17a028d91b1ac7b"}, - {file = "pydantic_core-2.41.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca2322da745bf2eeb581fc9ea3bbb31147702163ccbcbf12a3bb630e4bf05e1d"}, - {file = "pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e8cd3577c796be7231dcf80badcf2e0835a46665eaafd8ace124d886bab4d700"}, - {file = "pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:1cae8851e174c83633f0833e90636832857297900133705ee158cf79d40f03e6"}, - {file = "pydantic_core-2.41.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a26d950449aae348afe1ac8be5525a00ae4235309b729ad4d3399623125b43c9"}, - {file = "pydantic_core-2.41.4-cp310-cp310-win32.whl", hash = "sha256:0cf2a1f599efe57fa0051312774280ee0f650e11152325e41dfd3018ef2c1b57"}, - {file = "pydantic_core-2.41.4-cp310-cp310-win_amd64.whl", hash = "sha256:a8c2e340d7e454dc3340d3d2e8f23558ebe78c98aa8f68851b04dcb7bc37abdc"}, - {file = "pydantic_core-2.41.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:28ff11666443a1a8cf2a044d6a545ebffa8382b5f7973f22c36109205e65dc80"}, - {file = "pydantic_core-2.41.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:61760c3925d4633290292bad462e0f737b840508b4f722247d8729684f6539ae"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eae547b7315d055b0de2ec3965643b0ab82ad0106a7ffd29615ee9f266a02827"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef9ee5471edd58d1fcce1c80ffc8783a650e3e3a193fe90d52e43bb4d87bff1f"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15dd504af121caaf2c95cb90c0ebf71603c53de98305621b94da0f967e572def"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a926768ea49a8af4d36abd6a8968b8790f7f76dd7cbd5a4c180db2b4ac9a3a2"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916b9b7d134bff5440098a4deb80e4cb623e68974a87883299de9124126c2a8"}, - {file = "pydantic_core-2.41.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5cf90535979089df02e6f17ffd076f07237efa55b7343d98760bde8743c4b265"}, - {file = "pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7533c76fa647fade2d7ec75ac5cc079ab3f34879626dae5689b27790a6cf5a5c"}, - {file = "pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:37e516bca9264cbf29612539801ca3cd5d1be465f940417b002905e6ed79d38a"}, - {file = "pydantic_core-2.41.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0c19cb355224037c83642429b8ce261ae108e1c5fbf5c028bac63c77b0f8646e"}, - {file = "pydantic_core-2.41.4-cp311-cp311-win32.whl", hash = "sha256:09c2a60e55b357284b5f31f5ab275ba9f7f70b7525e18a132ec1f9160b4f1f03"}, - {file = "pydantic_core-2.41.4-cp311-cp311-win_amd64.whl", hash = "sha256:711156b6afb5cb1cb7c14a2cc2c4a8b4c717b69046f13c6b332d8a0a8f41ca3e"}, - {file = "pydantic_core-2.41.4-cp311-cp311-win_arm64.whl", hash = "sha256:6cb9cf7e761f4f8a8589a45e49ed3c0d92d1d696a45a6feaee8c904b26efc2db"}, - {file = "pydantic_core-2.41.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ab06d77e053d660a6faaf04894446df7b0a7e7aba70c2797465a0a1af00fc887"}, - {file = "pydantic_core-2.41.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c53ff33e603a9c1179a9364b0a24694f183717b2e0da2b5ad43c316c956901b2"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:304c54176af2c143bd181d82e77c15c41cbacea8872a2225dd37e6544dce9999"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:025ba34a4cf4fb32f917d5d188ab5e702223d3ba603be4d8aca2f82bede432a4"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9f5f30c402ed58f90c70e12eff65547d3ab74685ffe8283c719e6bead8ef53f"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd96e5d15385d301733113bcaa324c8bcf111275b7675a9c6e88bfb19fc05e3b"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98f348cbb44fae6e9653c1055db7e29de67ea6a9ca03a5fa2c2e11a47cff0e47"}, - {file = "pydantic_core-2.41.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec22626a2d14620a83ca583c6f5a4080fa3155282718b6055c2ea48d3ef35970"}, - {file = "pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a95d4590b1f1a43bf33ca6d647b990a88f4a3824a8c4572c708f0b45a5290ed"}, - {file = "pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:f9672ab4d398e1b602feadcffcdd3af44d5f5e6ddc15bc7d15d376d47e8e19f8"}, - {file = "pydantic_core-2.41.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:84d8854db5f55fead3b579f04bda9a36461dab0730c5d570e1526483e7bb8431"}, - {file = "pydantic_core-2.41.4-cp312-cp312-win32.whl", hash = "sha256:9be1c01adb2ecc4e464392c36d17f97e9110fbbc906bcbe1c943b5b87a74aabd"}, - {file = "pydantic_core-2.41.4-cp312-cp312-win_amd64.whl", hash = "sha256:d682cf1d22bab22a5be08539dca3d1593488a99998f9f412137bc323179067ff"}, - {file = "pydantic_core-2.41.4-cp312-cp312-win_arm64.whl", hash = "sha256:833eebfd75a26d17470b58768c1834dfc90141b7afc6eb0429c21fc5a21dcfb8"}, - {file = "pydantic_core-2.41.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:85e050ad9e5f6fe1004eec65c914332e52f429bc0ae12d6fa2092407a462c746"}, - {file = "pydantic_core-2.41.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7393f1d64792763a48924ba31d1e44c2cfbc05e3b1c2c9abb4ceeadd912cced"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94dab0940b0d1fb28bcab847adf887c66a27a40291eedf0b473be58761c9799a"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:de7c42f897e689ee6f9e93c4bec72b99ae3b32a2ade1c7e4798e690ff5246e02"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:664b3199193262277b8b3cd1e754fb07f2c6023289c815a1e1e8fb415cb247b1"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d95b253b88f7d308b1c0b417c4624f44553ba4762816f94e6986819b9c273fb2"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1351f5bbdbbabc689727cb91649a00cb9ee7203e0a6e54e9f5ba9e22e384b84"}, - {file = "pydantic_core-2.41.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1affa4798520b148d7182da0615d648e752de4ab1a9566b7471bc803d88a062d"}, - {file = "pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7b74e18052fea4aa8dea2fb7dbc23d15439695da6cbe6cfc1b694af1115df09d"}, - {file = "pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:285b643d75c0e30abda9dc1077395624f314a37e3c09ca402d4015ef5979f1a2"}, - {file = "pydantic_core-2.41.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:f52679ff4218d713b3b33f88c89ccbf3a5c2c12ba665fb80ccc4192b4608dbab"}, - {file = "pydantic_core-2.41.4-cp313-cp313-win32.whl", hash = "sha256:ecde6dedd6fff127c273c76821bb754d793be1024bc33314a120f83a3c69460c"}, - {file = "pydantic_core-2.41.4-cp313-cp313-win_amd64.whl", hash = "sha256:d081a1f3800f05409ed868ebb2d74ac39dd0c1ff6c035b5162356d76030736d4"}, - {file = "pydantic_core-2.41.4-cp313-cp313-win_arm64.whl", hash = "sha256:f8e49c9c364a7edcbe2a310f12733aad95b022495ef2a8d653f645e5d20c1564"}, - {file = "pydantic_core-2.41.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ed97fd56a561f5eb5706cebe94f1ad7c13b84d98312a05546f2ad036bafe87f4"}, - {file = "pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a870c307bf1ee91fc58a9a61338ff780d01bfae45922624816878dce784095d2"}, - {file = "pydantic_core-2.41.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d25e97bc1f5f8f7985bdc2335ef9e73843bb561eb1fa6831fdfc295c1c2061cf"}, - {file = "pydantic_core-2.41.4-cp313-cp313t-win_amd64.whl", hash = "sha256:d405d14bea042f166512add3091c1af40437c2e7f86988f3915fabd27b1e9cd2"}, - {file = "pydantic_core-2.41.4-cp313-cp313t-win_arm64.whl", hash = "sha256:19f3684868309db5263a11bace3c45d93f6f24afa2ffe75a647583df22a2ff89"}, - {file = "pydantic_core-2.41.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:e9205d97ed08a82ebb9a307e92914bb30e18cdf6f6b12ca4bedadb1588a0bfe1"}, - {file = "pydantic_core-2.41.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:82df1f432b37d832709fbcc0e24394bba04a01b6ecf1ee87578145c19cde12ac"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3b4cc4539e055cfa39a3763c939f9d409eb40e85813257dcd761985a108554"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1eb1754fce47c63d2ff57fdb88c351a6c0150995890088b33767a10218eaa4e"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6ab5ab30ef325b443f379ddb575a34969c333004fca5a1daa0133a6ffaad616"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:31a41030b1d9ca497634092b46481b937ff9397a86f9f51bd41c4767b6fc04af"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a44ac1738591472c3d020f61c6df1e4015180d6262ebd39bf2aeb52571b60f12"}, - {file = "pydantic_core-2.41.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d72f2b5e6e82ab8f94ea7d0d42f83c487dc159c5240d8f83beae684472864e2d"}, - {file = "pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c4d1e854aaf044487d31143f541f7aafe7b482ae72a022c664b2de2e466ed0ad"}, - {file = "pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b568af94267729d76e6ee5ececda4e283d07bbb28e8148bb17adad93d025d25a"}, - {file = "pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6d55fb8b1e8929b341cc313a81a26e0d48aa3b519c1dbaadec3a6a2b4fcad025"}, - {file = "pydantic_core-2.41.4-cp314-cp314-win32.whl", hash = "sha256:5b66584e549e2e32a1398df11da2e0a7eff45d5c2d9db9d5667c5e6ac764d77e"}, - {file = "pydantic_core-2.41.4-cp314-cp314-win_amd64.whl", hash = "sha256:557a0aab88664cc552285316809cab897716a372afaf8efdbef756f8b890e894"}, - {file = "pydantic_core-2.41.4-cp314-cp314-win_arm64.whl", hash = "sha256:3f1ea6f48a045745d0d9f325989d8abd3f1eaf47dd00485912d1a3a63c623a8d"}, - {file = "pydantic_core-2.41.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6c1fe4c5404c448b13188dd8bd2ebc2bdd7e6727fa61ff481bcc2cca894018da"}, - {file = "pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:523e7da4d43b113bf8e7b49fa4ec0c35bf4fe66b2230bfc5c13cc498f12c6c3e"}, - {file = "pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5729225de81fb65b70fdb1907fcf08c75d498f4a6f15af005aabb1fdadc19dfa"}, - {file = "pydantic_core-2.41.4-cp314-cp314t-win_amd64.whl", hash = "sha256:de2cfbb09e88f0f795fd90cf955858fc2c691df65b1f21f0aa00b99f3fbc661d"}, - {file = "pydantic_core-2.41.4-cp314-cp314t-win_arm64.whl", hash = "sha256:d34f950ae05a83e0ede899c595f312ca976023ea1db100cd5aa188f7005e3ab0"}, - {file = "pydantic_core-2.41.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:646e76293345954acea6966149683047b7b2ace793011922208c8e9da12b0062"}, - {file = "pydantic_core-2.41.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cc8e85a63085a137d286e2791037f5fdfff0aabb8b899483ca9c496dd5797338"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:692c622c8f859a17c156492783902d8370ac7e121a611bd6fe92cc71acf9ee8d"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1e2906efb1031a532600679b424ef1d95d9f9fb507f813951f23320903adbd7"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e04e2f7f8916ad3ddd417a7abdd295276a0bf216993d9318a5d61cc058209166"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df649916b81822543d1c8e0e1d079235f68acdc7d270c911e8425045a8cfc57e"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66c529f862fdba70558061bb936fe00ddbaaa0c647fd26e4a4356ef1d6561891"}, - {file = "pydantic_core-2.41.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3b4c5a1fd3a311563ed866c2c9b62da06cb6398bee186484ce95c820db71cb"}, - {file = "pydantic_core-2.41.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6e0fc40d84448f941df9b3334c4b78fe42f36e3bf631ad54c3047a0cdddc2514"}, - {file = "pydantic_core-2.41.4-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:44e7625332683b6c1c8b980461475cde9595eff94447500e80716db89b0da005"}, - {file = "pydantic_core-2.41.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:170ee6835f6c71081d031ef1c3b4dc4a12b9efa6a9540f93f95b82f3c7571ae8"}, - {file = "pydantic_core-2.41.4-cp39-cp39-win32.whl", hash = "sha256:3adf61415efa6ce977041ba9745183c0e1f637ca849773afa93833e04b163feb"}, - {file = "pydantic_core-2.41.4-cp39-cp39-win_amd64.whl", hash = "sha256:a238dd3feee263eeaeb7dc44aea4ba1364682c4f9f9467e6af5596ba322c2332"}, - {file = "pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:a1b2cfec3879afb742a7b0bcfa53e4f22ba96571c9e54d6a3afe1052d17d843b"}, - {file = "pydantic_core-2.41.4-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:d175600d975b7c244af6eb9c9041f10059f20b8bbffec9e33fdd5ee3f67cdc42"}, - {file = "pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f184d657fa4947ae5ec9c47bd7e917730fa1cbb78195037e32dcbab50aca5ee"}, - {file = "pydantic_core-2.41.4-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed810568aeffed3edc78910af32af911c835cc39ebbfacd1f0ab5dd53028e5c"}, - {file = "pydantic_core-2.41.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:4f5d640aeebb438517150fdeec097739614421900e4a08db4a3ef38898798537"}, - {file = "pydantic_core-2.41.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:4a9ab037b71927babc6d9e7fc01aea9e66dc2a4a34dff06ef0724a4049629f94"}, - {file = "pydantic_core-2.41.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4dab9484ec605c3016df9ad4fd4f9a390bc5d816a3b10c6550f8424bb80b18c"}, - {file = "pydantic_core-2.41.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8a5028425820731d8c6c098ab642d7b8b999758e24acae03ed38a66eca8335"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e5ab4fc177dd41536b3c32b2ea11380dd3d4619a385860621478ac2d25ceb00"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3d88d0054d3fa11ce936184896bed3c1c5441d6fa483b498fac6a5d0dd6f64a9"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b2a054a8725f05b4b6503357e0ac1c4e8234ad3b0c2ac130d6ffc66f0e170e2"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0d9db5a161c99375a0c68c058e227bee1d89303300802601d76a3d01f74e258"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:6273ea2c8ffdac7b7fda2653c49682db815aebf4a89243a6feccf5e36c18c347"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:4c973add636efc61de22530b2ef83a65f39b6d6f656df97f678720e20de26caa"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b69d1973354758007f46cf2d44a4f3d0933f10b6dc9bf15cf1356e037f6f731a"}, - {file = "pydantic_core-2.41.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3619320641fd212aaf5997b6ca505e97540b7e16418f4a241f44cdf108ffb50d"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:491535d45cd7ad7e4a2af4a5169b0d07bebf1adfd164b0368da8aa41e19907a5"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:54d86c0cada6aba4ec4c047d0e348cbad7063b87ae0f005d9f8c9ad04d4a92a2"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca1124aced216b2500dc2609eade086d718e8249cb9696660ab447d50a758bd"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c9024169becccf0cb470ada03ee578d7348c119a0d42af3dcf9eda96e3a247c"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:26895a4268ae5a2849269f4991cdc97236e4b9c010e51137becf25182daac405"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:ca4df25762cf71308c446e33c9b1fdca2923a3f13de616e2a949f38bf21ff5a8"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:5a28fcedd762349519276c36634e71853b4541079cab4acaaac60c4421827308"}, - {file = "pydantic_core-2.41.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c173ddcd86afd2535e2b695217e82191580663a1d1928239f877f5a1649ef39f"}, - {file = "pydantic_core-2.41.4.tar.gz", hash = "sha256:70e47929a9d4a1905a67e4b687d5946026390568a8e952b92824118063cee4d5"}, +files = [ + {file = "pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146"}, + {file = "pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49"}, + {file = "pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba"}, + {file = "pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9"}, + {file = "pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6"}, + {file = "pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f"}, + {file = "pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7"}, + {file = "pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3"}, + {file = "pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9"}, + {file = "pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd"}, + {file = "pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a"}, + {file = "pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008"}, + {file = "pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf"}, + {file = "pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3"}, + {file = "pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460"}, + {file = "pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51"}, + {file = "pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e"}, ] [package.dependencies] @@ -1684,7 +1706,6 @@ version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" -groups = ["dev", "docs"] files = [ {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, @@ -1699,7 +1720,6 @@ version = "8.4.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79"}, {file = "pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01"}, @@ -1723,7 +1743,6 @@ version = "1.1.1" description = "Pytest support for asyncio" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pytest_asyncio-1.1.1-py3-none-any.whl", hash = "sha256:726339d30fcfde24691f589445b9b67d058b311ac632b1d704e97f20f1d878da"}, {file = "pytest_asyncio-1.1.1.tar.gz", hash = "sha256:b72d215c38e2c91dbb32f275e0b5be69602d7869910e109360e375129960a649"}, @@ -1743,7 +1762,6 @@ version = "1.1.3" description = "pytest-httpserver is a httpserver for pytest" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pytest_httpserver-1.1.3-py3-none-any.whl", hash = "sha256:5f84757810233e19e2bb5287f3826a71c97a3740abe3a363af9155c0f82fdbb9"}, {file = "pytest_httpserver-1.1.3.tar.gz", hash = "sha256:af819d6b533f84b4680b9416a5b3f67f1df3701f1da54924afd4d6e4ba5917ec"}, @@ -1758,7 +1776,6 @@ version = "2.4.0" description = "pytest plugin to abort hanging tests" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2"}, {file = "pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a"}, @@ -1773,7 +1790,6 @@ version = "3.8.0" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88"}, {file = "pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1"}, @@ -1794,7 +1810,6 @@ version = "6.0.3" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, @@ -1877,7 +1892,6 @@ version = "0.37.0" description = "JSON Referencing + Python" optional = false python-versions = ">=3.10" -groups = ["dev"] files = [ {file = "referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231"}, {file = "referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8"}, @@ -1890,127 +1904,126 @@ typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""} [[package]] name = "regex" -version = "2025.9.18" +version = "2025.11.3" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "regex-2025.9.18-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:12296202480c201c98a84aecc4d210592b2f55e200a1d193235c4db92b9f6788"}, - {file = "regex-2025.9.18-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:220381f1464a581f2ea988f2220cf2a67927adcef107d47d6897ba5a2f6d51a4"}, - {file = "regex-2025.9.18-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:87f681bfca84ebd265278b5daa1dcb57f4db315da3b5d044add7c30c10442e61"}, - {file = "regex-2025.9.18-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:34d674cbba70c9398074c8a1fcc1a79739d65d1105de2a3c695e2b05ea728251"}, - {file = "regex-2025.9.18-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:385c9b769655cb65ea40b6eea6ff763cbb6d69b3ffef0b0db8208e1833d4e746"}, - {file = "regex-2025.9.18-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8900b3208e022570ae34328712bef6696de0804c122933414014bae791437ab2"}, - {file = "regex-2025.9.18-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c204e93bf32cd7a77151d44b05eb36f469d0898e3fba141c026a26b79d9914a0"}, - {file = "regex-2025.9.18-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3acc471d1dd7e5ff82e6cacb3b286750decd949ecd4ae258696d04f019817ef8"}, - {file = "regex-2025.9.18-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6479d5555122433728760e5f29edb4c2b79655a8deb681a141beb5c8a025baea"}, - {file = "regex-2025.9.18-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:431bd2a8726b000eb6f12429c9b438a24062a535d06783a93d2bcbad3698f8a8"}, - {file = "regex-2025.9.18-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0cc3521060162d02bd36927e20690129200e5ac9d2c6d32b70368870b122db25"}, - {file = "regex-2025.9.18-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a021217b01be2d51632ce056d7a837d3fa37c543ede36e39d14063176a26ae29"}, - {file = "regex-2025.9.18-cp310-cp310-win32.whl", hash = "sha256:4a12a06c268a629cb67cc1d009b7bb0be43e289d00d5111f86a2efd3b1949444"}, - {file = "regex-2025.9.18-cp310-cp310-win_amd64.whl", hash = "sha256:47acd811589301298c49db2c56bde4f9308d6396da92daf99cba781fa74aa450"}, - {file = "regex-2025.9.18-cp310-cp310-win_arm64.whl", hash = "sha256:16bd2944e77522275e5ee36f867e19995bcaa533dcb516753a26726ac7285442"}, - {file = "regex-2025.9.18-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:51076980cd08cd13c88eb7365427ae27f0d94e7cebe9ceb2bb9ffdae8fc4d82a"}, - {file = "regex-2025.9.18-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:828446870bd7dee4e0cbeed767f07961aa07f0ea3129f38b3ccecebc9742e0b8"}, - {file = "regex-2025.9.18-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c28821d5637866479ec4cc23b8c990f5bc6dd24e5e4384ba4a11d38a526e1414"}, - {file = "regex-2025.9.18-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:726177ade8e481db669e76bf99de0b278783be8acd11cef71165327abd1f170a"}, - {file = "regex-2025.9.18-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f5cca697da89b9f8ea44115ce3130f6c54c22f541943ac8e9900461edc2b8bd4"}, - {file = "regex-2025.9.18-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dfbde38f38004703c35666a1e1c088b778e35d55348da2b7b278914491698d6a"}, - {file = "regex-2025.9.18-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f2f422214a03fab16bfa495cfec72bee4aaa5731843b771860a471282f1bf74f"}, - {file = "regex-2025.9.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a295916890f4df0902e4286bc7223ee7f9e925daa6dcdec4192364255b70561a"}, - {file = "regex-2025.9.18-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:5db95ff632dbabc8c38c4e82bf545ab78d902e81160e6e455598014f0abe66b9"}, - {file = "regex-2025.9.18-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fb967eb441b0f15ae610b7069bdb760b929f267efbf522e814bbbfffdf125ce2"}, - {file = "regex-2025.9.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f04d2f20da4053d96c08f7fde6e1419b7ec9dbcee89c96e3d731fca77f411b95"}, - {file = "regex-2025.9.18-cp311-cp311-win32.whl", hash = "sha256:895197241fccf18c0cea7550c80e75f185b8bd55b6924fcae269a1a92c614a07"}, - {file = "regex-2025.9.18-cp311-cp311-win_amd64.whl", hash = "sha256:7e2b414deae99166e22c005e154a5513ac31493db178d8aec92b3269c9cce8c9"}, - {file = "regex-2025.9.18-cp311-cp311-win_arm64.whl", hash = "sha256:fb137ec7c5c54f34a25ff9b31f6b7b0c2757be80176435bf367111e3f71d72df"}, - {file = "regex-2025.9.18-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:436e1b31d7efd4dcd52091d076482031c611dde58bf9c46ca6d0a26e33053a7e"}, - {file = "regex-2025.9.18-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c190af81e5576b9c5fdc708f781a52ff20f8b96386c6e2e0557a78402b029f4a"}, - {file = "regex-2025.9.18-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e4121f1ce2b2b5eec4b397cc1b277686e577e658d8f5870b7eb2d726bd2300ab"}, - {file = "regex-2025.9.18-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:300e25dbbf8299d87205e821a201057f2ef9aa3deb29caa01cd2cac669e508d5"}, - {file = "regex-2025.9.18-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7b47fcf9f5316c0bdaf449e879407e1b9937a23c3b369135ca94ebc8d74b1742"}, - {file = "regex-2025.9.18-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:57a161bd3acaa4b513220b49949b07e252165e6b6dc910ee7617a37ff4f5b425"}, - {file = "regex-2025.9.18-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f130c3a7845ba42de42f380fff3c8aebe89a810747d91bcf56d40a069f15352"}, - {file = "regex-2025.9.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f96fa342b6f54dcba928dd452e8d8cb9f0d63e711d1721cd765bb9f73bb048d"}, - {file = "regex-2025.9.18-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0f0d676522d68c207828dcd01fb6f214f63f238c283d9f01d85fc664c7c85b56"}, - {file = "regex-2025.9.18-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:40532bff8a1a0621e7903ae57fce88feb2e8a9a9116d341701302c9302aef06e"}, - {file = "regex-2025.9.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:039f11b618ce8d71a1c364fdee37da1012f5a3e79b1b2819a9f389cd82fd6282"}, - {file = "regex-2025.9.18-cp312-cp312-win32.whl", hash = "sha256:e1dd06f981eb226edf87c55d523131ade7285137fbde837c34dc9d1bf309f459"}, - {file = "regex-2025.9.18-cp312-cp312-win_amd64.whl", hash = "sha256:3d86b5247bf25fa3715e385aa9ff272c307e0636ce0c9595f64568b41f0a9c77"}, - {file = "regex-2025.9.18-cp312-cp312-win_arm64.whl", hash = "sha256:032720248cbeeae6444c269b78cb15664458b7bb9ed02401d3da59fe4d68c3a5"}, - {file = "regex-2025.9.18-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2a40f929cd907c7e8ac7566ac76225a77701a6221bca937bdb70d56cb61f57b2"}, - {file = "regex-2025.9.18-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c90471671c2cdf914e58b6af62420ea9ecd06d1554d7474d50133ff26ae88feb"}, - {file = "regex-2025.9.18-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a351aff9e07a2dabb5022ead6380cff17a4f10e4feb15f9100ee56c4d6d06af"}, - {file = "regex-2025.9.18-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc4b8e9d16e20ddfe16430c23468a8707ccad3365b06d4536142e71823f3ca29"}, - {file = "regex-2025.9.18-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b8cdbddf2db1c5e80338ba2daa3cfa3dec73a46fff2a7dda087c8efbf12d62f"}, - {file = "regex-2025.9.18-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a276937d9d75085b2c91fb48244349c6954f05ee97bba0963ce24a9d915b8b68"}, - {file = "regex-2025.9.18-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:92a8e375ccdc1256401c90e9dc02b8642894443d549ff5e25e36d7cf8a80c783"}, - {file = "regex-2025.9.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0dc6893b1f502d73037cf807a321cdc9be29ef3d6219f7970f842475873712ac"}, - {file = "regex-2025.9.18-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a61e85bfc63d232ac14b015af1261f826260c8deb19401c0597dbb87a864361e"}, - {file = "regex-2025.9.18-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1ef86a9ebc53f379d921fb9a7e42b92059ad3ee800fcd9e0fe6181090e9f6c23"}, - {file = "regex-2025.9.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d3bc882119764ba3a119fbf2bd4f1b47bc56c1da5d42df4ed54ae1e8e66fdf8f"}, - {file = "regex-2025.9.18-cp313-cp313-win32.whl", hash = "sha256:3810a65675845c3bdfa58c3c7d88624356dd6ee2fc186628295e0969005f928d"}, - {file = "regex-2025.9.18-cp313-cp313-win_amd64.whl", hash = "sha256:16eaf74b3c4180ede88f620f299e474913ab6924d5c4b89b3833bc2345d83b3d"}, - {file = "regex-2025.9.18-cp313-cp313-win_arm64.whl", hash = "sha256:4dc98ba7dd66bd1261927a9f49bd5ee2bcb3660f7962f1ec02617280fc00f5eb"}, - {file = "regex-2025.9.18-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:fe5d50572bc885a0a799410a717c42b1a6b50e2f45872e2b40f4f288f9bce8a2"}, - {file = "regex-2025.9.18-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b9d9a2d6cda6621551ca8cf7a06f103adf72831153f3c0d982386110870c4d3"}, - {file = "regex-2025.9.18-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:13202e4c4ac0ef9a317fff817674b293c8f7e8c68d3190377d8d8b749f566e12"}, - {file = "regex-2025.9.18-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:874ff523b0fecffb090f80ae53dc93538f8db954c8bb5505f05b7787ab3402a0"}, - {file = "regex-2025.9.18-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d13ab0490128f2bb45d596f754148cd750411afc97e813e4b3a61cf278a23bb6"}, - {file = "regex-2025.9.18-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:05440bc172bc4b4b37fb9667e796597419404dbba62e171e1f826d7d2a9ebcef"}, - {file = "regex-2025.9.18-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5514b8e4031fdfaa3d27e92c75719cbe7f379e28cacd939807289bce76d0e35a"}, - {file = "regex-2025.9.18-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:65d3c38c39efce73e0d9dc019697b39903ba25b1ad45ebbd730d2cf32741f40d"}, - {file = "regex-2025.9.18-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ae77e447ebc144d5a26d50055c6ddba1d6ad4a865a560ec7200b8b06bc529368"}, - {file = "regex-2025.9.18-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e3ef8cf53dc8df49d7e28a356cf824e3623764e9833348b655cfed4524ab8a90"}, - {file = "regex-2025.9.18-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9feb29817df349c976da9a0debf775c5c33fc1c8ad7b9f025825da99374770b7"}, - {file = "regex-2025.9.18-cp313-cp313t-win32.whl", hash = "sha256:168be0d2f9b9d13076940b1ed774f98595b4e3c7fc54584bba81b3cc4181742e"}, - {file = "regex-2025.9.18-cp313-cp313t-win_amd64.whl", hash = "sha256:d59ecf3bb549e491c8104fea7313f3563c7b048e01287db0a90485734a70a730"}, - {file = "regex-2025.9.18-cp313-cp313t-win_arm64.whl", hash = "sha256:dbef80defe9fb21310948a2595420b36c6d641d9bea4c991175829b2cc4bc06a"}, - {file = "regex-2025.9.18-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:c6db75b51acf277997f3adcd0ad89045d856190d13359f15ab5dda21581d9129"}, - {file = "regex-2025.9.18-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8f9698b6f6895d6db810e0bda5364f9ceb9e5b11328700a90cae573574f61eea"}, - {file = "regex-2025.9.18-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29cd86aa7cb13a37d0f0d7c21d8d949fe402ffa0ea697e635afedd97ab4b69f1"}, - {file = "regex-2025.9.18-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c9f285a071ee55cd9583ba24dde006e53e17780bb309baa8e4289cd472bcc47"}, - {file = "regex-2025.9.18-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5adf266f730431e3be9021d3e5b8d5ee65e563fec2883ea8093944d21863b379"}, - {file = "regex-2025.9.18-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1137cabc0f38807de79e28d3f6e3e3f2cc8cfb26bead754d02e6d1de5f679203"}, - {file = "regex-2025.9.18-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7cc9e5525cada99699ca9223cce2d52e88c52a3d2a0e842bd53de5497c604164"}, - {file = "regex-2025.9.18-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bbb9246568f72dce29bcd433517c2be22c7791784b223a810225af3b50d1aafb"}, - {file = "regex-2025.9.18-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:6a52219a93dd3d92c675383efff6ae18c982e2d7651c792b1e6d121055808743"}, - {file = "regex-2025.9.18-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:ae9b3840c5bd456780e3ddf2f737ab55a79b790f6409182012718a35c6d43282"}, - {file = "regex-2025.9.18-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d488c236ac497c46a5ac2005a952c1a0e22a07be9f10c3e735bc7d1209a34773"}, - {file = "regex-2025.9.18-cp314-cp314-win32.whl", hash = "sha256:0c3506682ea19beefe627a38872d8da65cc01ffa25ed3f2e422dffa1474f0788"}, - {file = "regex-2025.9.18-cp314-cp314-win_amd64.whl", hash = "sha256:57929d0f92bebb2d1a83af372cd0ffba2263f13f376e19b1e4fa32aec4efddc3"}, - {file = "regex-2025.9.18-cp314-cp314-win_arm64.whl", hash = "sha256:6a4b44df31d34fa51aa5c995d3aa3c999cec4d69b9bd414a8be51984d859f06d"}, - {file = "regex-2025.9.18-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:b176326bcd544b5e9b17d6943f807697c0cb7351f6cfb45bf5637c95ff7e6306"}, - {file = "regex-2025.9.18-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:0ffd9e230b826b15b369391bec167baed57c7ce39efc35835448618860995946"}, - {file = "regex-2025.9.18-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ec46332c41add73f2b57e2f5b642f991f6b15e50e9f86285e08ffe3a512ac39f"}, - {file = "regex-2025.9.18-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b80fa342ed1ea095168a3f116637bd1030d39c9ff38dc04e54ef7c521e01fc95"}, - {file = "regex-2025.9.18-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f4d97071c0ba40f0cf2a93ed76e660654c399a0a04ab7d85472239460f3da84b"}, - {file = "regex-2025.9.18-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0ac936537ad87cef9e0e66c5144484206c1354224ee811ab1519a32373e411f3"}, - {file = "regex-2025.9.18-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dec57f96d4def58c422d212d414efe28218d58537b5445cf0c33afb1b4768571"}, - {file = "regex-2025.9.18-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:48317233294648bf7cd068857f248e3a57222259a5304d32c7552e2284a1b2ad"}, - {file = "regex-2025.9.18-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:274687e62ea3cf54846a9b25fc48a04459de50af30a7bd0b61a9e38015983494"}, - {file = "regex-2025.9.18-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:a78722c86a3e7e6aadf9579e3b0ad78d955f2d1f1a8ca4f67d7ca258e8719d4b"}, - {file = "regex-2025.9.18-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:06104cd203cdef3ade989a1c45b6215bf42f8b9dd705ecc220c173233f7cba41"}, - {file = "regex-2025.9.18-cp314-cp314t-win32.whl", hash = "sha256:2e1eddc06eeaffd249c0adb6fafc19e2118e6308c60df9db27919e96b5656096"}, - {file = "regex-2025.9.18-cp314-cp314t-win_amd64.whl", hash = "sha256:8620d247fb8c0683ade51217b459cb4a1081c0405a3072235ba43a40d355c09a"}, - {file = "regex-2025.9.18-cp314-cp314t-win_arm64.whl", hash = "sha256:b7531a8ef61de2c647cdf68b3229b071e46ec326b3138b2180acb4275f470b01"}, - {file = "regex-2025.9.18-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3dbcfcaa18e9480669030d07371713c10b4f1a41f791ffa5cb1a99f24e777f40"}, - {file = "regex-2025.9.18-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1e85f73ef7095f0380208269055ae20524bfde3f27c5384126ddccf20382a638"}, - {file = "regex-2025.9.18-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9098e29b3ea4ffffeade423f6779665e2a4f8db64e699c0ed737ef0db6ba7b12"}, - {file = "regex-2025.9.18-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90b6b7a2d0f45b7ecaaee1aec6b362184d6596ba2092dd583ffba1b78dd0231c"}, - {file = "regex-2025.9.18-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c81b892af4a38286101502eae7aec69f7cd749a893d9987a92776954f3943408"}, - {file = "regex-2025.9.18-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3b524d010973f2e1929aeb635418d468d869a5f77b52084d9f74c272189c251d"}, - {file = "regex-2025.9.18-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b498437c026a3d5d0be0020023ff76d70ae4d77118e92f6f26c9d0423452446"}, - {file = "regex-2025.9.18-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0716e4d6e58853d83f6563f3cf25c281ff46cf7107e5f11879e32cb0b59797d9"}, - {file = "regex-2025.9.18-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:065b6956749379d41db2625f880b637d4acc14c0a4de0d25d609a62850e96d36"}, - {file = "regex-2025.9.18-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:d4a691494439287c08ddb9b5793da605ee80299dd31e95fa3f323fac3c33d9d4"}, - {file = "regex-2025.9.18-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ef8d10cc0989565bcbe45fb4439f044594d5c2b8919d3d229ea2c4238f1d55b0"}, - {file = "regex-2025.9.18-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4baeb1b16735ac969a7eeecc216f1f8b7caf60431f38a2671ae601f716a32d25"}, - {file = "regex-2025.9.18-cp39-cp39-win32.whl", hash = "sha256:8e5f41ad24a1e0b5dfcf4c4e5d9f5bd54c895feb5708dd0c1d0d35693b24d478"}, - {file = "regex-2025.9.18-cp39-cp39-win_amd64.whl", hash = "sha256:50e8290707f2fb8e314ab3831e594da71e062f1d623b05266f8cfe4db4949afd"}, - {file = "regex-2025.9.18-cp39-cp39-win_arm64.whl", hash = "sha256:039a9d7195fd88c943d7c777d4941e8ef736731947becce773c31a1009cb3c35"}, - {file = "regex-2025.9.18.tar.gz", hash = "sha256:c5ba23274c61c6fef447ba6a39333297d0c247f53059dba0bca415cac511edc4"}, +files = [ + {file = "regex-2025.11.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2b441a4ae2c8049106e8b39973bfbddfb25a179dda2bdb99b0eeb60c40a6a3af"}, + {file = "regex-2025.11.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2fa2eed3f76677777345d2f81ee89f5de2f5745910e805f7af7386a920fa7313"}, + {file = "regex-2025.11.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d8b4a27eebd684319bdf473d39f1d79eed36bf2cd34bd4465cdb4618d82b3d56"}, + {file = "regex-2025.11.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cf77eac15bd264986c4a2c63353212c095b40f3affb2bc6b4ef80c4776c1a28"}, + {file = "regex-2025.11.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b7f9ee819f94c6abfa56ec7b1dbab586f41ebbdc0a57e6524bd5e7f487a878c7"}, + {file = "regex-2025.11.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:838441333bc90b829406d4a03cb4b8bf7656231b84358628b0406d803931ef32"}, + {file = "regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cfe6d3f0c9e3b7e8c0c694b24d25e677776f5ca26dce46fd6b0489f9c8339391"}, + {file = "regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2ab815eb8a96379a27c3b6157fcb127c8f59c36f043c1678110cea492868f1d5"}, + {file = "regex-2025.11.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:728a9d2d173a65b62bdc380b7932dd8e74ed4295279a8fe1021204ce210803e7"}, + {file = "regex-2025.11.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:509dc827f89c15c66a0c216331260d777dd6c81e9a4e4f830e662b0bb296c313"}, + {file = "regex-2025.11.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:849202cd789e5f3cf5dcc7822c34b502181b4824a65ff20ce82da5524e45e8e9"}, + {file = "regex-2025.11.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b6f78f98741dcc89607c16b1e9426ee46ce4bf31ac5e6b0d40e81c89f3481ea5"}, + {file = "regex-2025.11.3-cp310-cp310-win32.whl", hash = "sha256:149eb0bba95231fb4f6d37c8f760ec9fa6fabf65bab555e128dde5f2475193ec"}, + {file = "regex-2025.11.3-cp310-cp310-win_amd64.whl", hash = "sha256:ee3a83ce492074c35a74cc76cf8235d49e77b757193a5365ff86e3f2f93db9fd"}, + {file = "regex-2025.11.3-cp310-cp310-win_arm64.whl", hash = "sha256:38af559ad934a7b35147716655d4a2f79fcef2d695ddfe06a06ba40ae631fa7e"}, + {file = "regex-2025.11.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eadade04221641516fa25139273505a1c19f9bf97589a05bc4cfcd8b4a618031"}, + {file = "regex-2025.11.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:feff9e54ec0dd3833d659257f5c3f5322a12eee58ffa360984b716f8b92983f4"}, + {file = "regex-2025.11.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3b30bc921d50365775c09a7ed446359e5c0179e9e2512beec4a60cbcef6ddd50"}, + {file = "regex-2025.11.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f99be08cfead2020c7ca6e396c13543baea32343b7a9a5780c462e323bd8872f"}, + {file = "regex-2025.11.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6dd329a1b61c0ee95ba95385fb0c07ea0d3fe1a21e1349fa2bec272636217118"}, + {file = "regex-2025.11.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4c5238d32f3c5269d9e87be0cf096437b7622b6920f5eac4fd202468aaeb34d2"}, + {file = "regex-2025.11.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10483eefbfb0adb18ee9474498c9a32fcf4e594fbca0543bb94c48bac6183e2e"}, + {file = "regex-2025.11.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:78c2d02bb6e1da0720eedc0bad578049cad3f71050ef8cd065ecc87691bed2b0"}, + {file = "regex-2025.11.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e6b49cd2aad93a1790ce9cffb18964f6d3a4b0b3dbdbd5de094b65296fce6e58"}, + {file = "regex-2025.11.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:885b26aa3ee56433b630502dc3d36ba78d186a00cc535d3806e6bfd9ed3c70ab"}, + {file = "regex-2025.11.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ddd76a9f58e6a00f8772e72cff8ebcff78e022be95edf018766707c730593e1e"}, + {file = "regex-2025.11.3-cp311-cp311-win32.whl", hash = "sha256:3e816cc9aac1cd3cc9a4ec4d860f06d40f994b5c7b4d03b93345f44e08cc68bf"}, + {file = "regex-2025.11.3-cp311-cp311-win_amd64.whl", hash = "sha256:087511f5c8b7dfbe3a03f5d5ad0c2a33861b1fc387f21f6f60825a44865a385a"}, + {file = "regex-2025.11.3-cp311-cp311-win_arm64.whl", hash = "sha256:1ff0d190c7f68ae7769cd0313fe45820ba07ffebfddfaa89cc1eb70827ba0ddc"}, + {file = "regex-2025.11.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bc8ab71e2e31b16e40868a40a69007bc305e1109bd4658eb6cad007e0bf67c41"}, + {file = "regex-2025.11.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:22b29dda7e1f7062a52359fca6e58e548e28c6686f205e780b02ad8ef710de36"}, + {file = "regex-2025.11.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a91e4a29938bc1a082cc28fdea44be420bf2bebe2665343029723892eb073e1"}, + {file = "regex-2025.11.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08b884f4226602ad40c5d55f52bf91a9df30f513864e0054bad40c0e9cf1afb7"}, + {file = "regex-2025.11.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3e0b11b2b2433d1c39c7c7a30e3f3d0aeeea44c2a8d0bae28f6b95f639927a69"}, + {file = "regex-2025.11.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87eb52a81ef58c7ba4d45c3ca74e12aa4b4e77816f72ca25258a85b3ea96cb48"}, + {file = "regex-2025.11.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a12ab1f5c29b4e93db518f5e3872116b7e9b1646c9f9f426f777b50d44a09e8c"}, + {file = "regex-2025.11.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7521684c8c7c4f6e88e35ec89680ee1aa8358d3f09d27dfbdf62c446f5d4c695"}, + {file = "regex-2025.11.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7fe6e5440584e94cc4b3f5f4d98a25e29ca12dccf8873679a635638349831b98"}, + {file = "regex-2025.11.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:8e026094aa12b43f4fd74576714e987803a315c76edb6b098b9809db5de58f74"}, + {file = "regex-2025.11.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:435bbad13e57eb5606a68443af62bed3556de2f46deb9f7d4237bc2f1c9fb3a0"}, + {file = "regex-2025.11.3-cp312-cp312-win32.whl", hash = "sha256:3839967cf4dc4b985e1570fd8d91078f0c519f30491c60f9ac42a8db039be204"}, + {file = "regex-2025.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:e721d1b46e25c481dc5ded6f4b3f66c897c58d2e8cfdf77bbced84339108b0b9"}, + {file = "regex-2025.11.3-cp312-cp312-win_arm64.whl", hash = "sha256:64350685ff08b1d3a6fff33f45a9ca183dc1d58bbfe4981604e70ec9801bbc26"}, + {file = "regex-2025.11.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c1e448051717a334891f2b9a620fe36776ebf3dd8ec46a0b877c8ae69575feb4"}, + {file = "regex-2025.11.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b5aca4d5dfd7fbfbfbdaf44850fcc7709a01146a797536a8f84952e940cca76"}, + {file = "regex-2025.11.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:04d2765516395cf7dda331a244a3282c0f5ae96075f728629287dfa6f76ba70a"}, + {file = "regex-2025.11.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d9903ca42bfeec4cebedba8022a7c97ad2aab22e09573ce9976ba01b65e4361"}, + {file = "regex-2025.11.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:639431bdc89d6429f6721625e8129413980ccd62e9d3f496be618a41d205f160"}, + {file = "regex-2025.11.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f117efad42068f9715677c8523ed2be1518116d1c49b1dd17987716695181efe"}, + {file = "regex-2025.11.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4aecb6f461316adf9f1f0f6a4a1a3d79e045f9b71ec76055a791affa3b285850"}, + {file = "regex-2025.11.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b3a5f320136873cc5561098dfab677eea139521cb9a9e8db98b7e64aef44cbc"}, + {file = "regex-2025.11.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:75fa6f0056e7efb1f42a1c34e58be24072cb9e61a601340cc1196ae92326a4f9"}, + {file = "regex-2025.11.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:dbe6095001465294f13f1adcd3311e50dd84e5a71525f20a10bd16689c61ce0b"}, + {file = "regex-2025.11.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:454d9b4ae7881afbc25015b8627c16d88a597479b9dea82b8c6e7e2e07240dc7"}, + {file = "regex-2025.11.3-cp313-cp313-win32.whl", hash = "sha256:28ba4d69171fc6e9896337d4fc63a43660002b7da53fc15ac992abcf3410917c"}, + {file = "regex-2025.11.3-cp313-cp313-win_amd64.whl", hash = "sha256:bac4200befe50c670c405dc33af26dad5a3b6b255dd6c000d92fe4629f9ed6a5"}, + {file = "regex-2025.11.3-cp313-cp313-win_arm64.whl", hash = "sha256:2292cd5a90dab247f9abe892ac584cb24f0f54680c73fcb4a7493c66c2bf2467"}, + {file = "regex-2025.11.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:1eb1ebf6822b756c723e09f5186473d93236c06c579d2cc0671a722d2ab14281"}, + {file = "regex-2025.11.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1e00ec2970aab10dc5db34af535f21fcf32b4a31d99e34963419636e2f85ae39"}, + {file = "regex-2025.11.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a4cb042b615245d5ff9b3794f56be4138b5adc35a4166014d31d1814744148c7"}, + {file = "regex-2025.11.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44f264d4bf02f3176467d90b294d59bf1db9fe53c141ff772f27a8b456b2a9ed"}, + {file = "regex-2025.11.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7be0277469bf3bd7a34a9c57c1b6a724532a0d235cd0dc4e7f4316f982c28b19"}, + {file = "regex-2025.11.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0d31e08426ff4b5b650f68839f5af51a92a5b51abd8554a60c2fbc7c71f25d0b"}, + {file = "regex-2025.11.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e43586ce5bd28f9f285a6e729466841368c4a0353f6fd08d4ce4630843d3648a"}, + {file = "regex-2025.11.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0f9397d561a4c16829d4e6ff75202c1c08b68a3bdbfe29dbfcdb31c9830907c6"}, + {file = "regex-2025.11.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:dd16e78eb18ffdb25ee33a0682d17912e8cc8a770e885aeee95020046128f1ce"}, + {file = "regex-2025.11.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:ffcca5b9efe948ba0661e9df0fa50d2bc4b097c70b9810212d6b62f05d83b2dd"}, + {file = "regex-2025.11.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c56b4d162ca2b43318ac671c65bd4d563e841a694ac70e1a976ac38fcf4ca1d2"}, + {file = "regex-2025.11.3-cp313-cp313t-win32.whl", hash = "sha256:9ddc42e68114e161e51e272f667d640f97e84a2b9ef14b7477c53aac20c2d59a"}, + {file = "regex-2025.11.3-cp313-cp313t-win_amd64.whl", hash = "sha256:7a7c7fdf755032ffdd72c77e3d8096bdcb0eb92e89e17571a196f03d88b11b3c"}, + {file = "regex-2025.11.3-cp313-cp313t-win_arm64.whl", hash = "sha256:df9eb838c44f570283712e7cff14c16329a9f0fb19ca492d21d4b7528ee6821e"}, + {file = "regex-2025.11.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9697a52e57576c83139d7c6f213d64485d3df5bf84807c35fa409e6c970801c6"}, + {file = "regex-2025.11.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e18bc3f73bd41243c9b38a6d9f2366cd0e0137a9aebe2d8ff76c5b67d4c0a3f4"}, + {file = "regex-2025.11.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:61a08bcb0ec14ff4e0ed2044aad948d0659604f824cbd50b55e30b0ec6f09c73"}, + {file = "regex-2025.11.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9c30003b9347c24bcc210958c5d167b9e4f9be786cb380a7d32f14f9b84674f"}, + {file = "regex-2025.11.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4e1e592789704459900728d88d41a46fe3969b82ab62945560a31732ffc19a6d"}, + {file = "regex-2025.11.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6538241f45eb5a25aa575dbba1069ad786f68a4f2773a29a2bd3dd1f9de787be"}, + {file = "regex-2025.11.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce22519c989bb72a7e6b36a199384c53db7722fe669ba891da75907fe3587db"}, + {file = "regex-2025.11.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:66d559b21d3640203ab9075797a55165d79017520685fb407b9234d72ab63c62"}, + {file = "regex-2025.11.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:669dcfb2e38f9e8c69507bace46f4889e3abbfd9b0c29719202883c0a603598f"}, + {file = "regex-2025.11.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:32f74f35ff0f25a5021373ac61442edcb150731fbaa28286bbc8bb1582c89d02"}, + {file = "regex-2025.11.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e6c7a21dffba883234baefe91bc3388e629779582038f75d2a5be918e250f0ed"}, + {file = "regex-2025.11.3-cp314-cp314-win32.whl", hash = "sha256:795ea137b1d809eb6836b43748b12634291c0ed55ad50a7d72d21edf1cd565c4"}, + {file = "regex-2025.11.3-cp314-cp314-win_amd64.whl", hash = "sha256:9f95fbaa0ee1610ec0fc6b26668e9917a582ba80c52cc6d9ada15e30aa9ab9ad"}, + {file = "regex-2025.11.3-cp314-cp314-win_arm64.whl", hash = "sha256:dfec44d532be4c07088c3de2876130ff0fbeeacaa89a137decbbb5f665855a0f"}, + {file = "regex-2025.11.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ba0d8a5d7f04f73ee7d01d974d47c5834f8a1b0224390e4fe7c12a3a92a78ecc"}, + {file = "regex-2025.11.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:442d86cf1cfe4faabf97db7d901ef58347efd004934da045c745e7b5bd57ac49"}, + {file = "regex-2025.11.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fd0a5e563c756de210bb964789b5abe4f114dacae9104a47e1a649b910361536"}, + {file = "regex-2025.11.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf3490bcbb985a1ae97b2ce9ad1c0f06a852d5b19dde9b07bdf25bf224248c95"}, + {file = "regex-2025.11.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3809988f0a8b8c9dcc0f92478d6501fac7200b9ec56aecf0ec21f4a2ec4b6009"}, + {file = "regex-2025.11.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f4ff94e58e84aedb9c9fce66d4ef9f27a190285b451420f297c9a09f2b9abee9"}, + {file = "regex-2025.11.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eb542fd347ce61e1321b0a6b945d5701528dca0cd9759c2e3bb8bd57e47964d"}, + {file = "regex-2025.11.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d6c2d5919075a1f2e413c00b056ea0c2f065b3f5fe83c3d07d325ab92dce51d6"}, + {file = "regex-2025.11.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:3f8bf11a4827cc7ce5a53d4ef6cddd5ad25595d3c1435ef08f76825851343154"}, + {file = "regex-2025.11.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:22c12d837298651e5550ac1d964e4ff57c3f56965fc1812c90c9fb2028eaf267"}, + {file = "regex-2025.11.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:62ba394a3dda9ad41c7c780f60f6e4a70988741415ae96f6d1bf6c239cf01379"}, + {file = "regex-2025.11.3-cp314-cp314t-win32.whl", hash = "sha256:4bf146dca15cdd53224a1bf46d628bd7590e4a07fbb69e720d561aea43a32b38"}, + {file = "regex-2025.11.3-cp314-cp314t-win_amd64.whl", hash = "sha256:adad1a1bcf1c9e76346e091d22d23ac54ef28e1365117d99521631078dfec9de"}, + {file = "regex-2025.11.3-cp314-cp314t-win_arm64.whl", hash = "sha256:c54f768482cef41e219720013cd05933b6f971d9562544d691c68699bf2b6801"}, + {file = "regex-2025.11.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:81519e25707fc076978c6143b81ea3dc853f176895af05bf7ec51effe818aeec"}, + {file = "regex-2025.11.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3bf28b1873a8af8bbb58c26cc56ea6e534d80053b41fb511a35795b6de507e6a"}, + {file = "regex-2025.11.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:856a25c73b697f2ce2a24e7968285579e62577a048526161a2c0f53090bea9f9"}, + {file = "regex-2025.11.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a3d571bd95fade53c86c0517f859477ff3a93c3fde10c9e669086f038e0f207"}, + {file = "regex-2025.11.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:732aea6de26051af97b94bc98ed86448821f839d058e5d259c72bf6d73ad0fc0"}, + {file = "regex-2025.11.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:51c1c1847128238f54930edb8805b660305dca164645a9fd29243f5610beea34"}, + {file = "regex-2025.11.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22dd622a402aad4558277305350699b2be14bc59f64d64ae1d928ce7d072dced"}, + {file = "regex-2025.11.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f3b5a391c7597ffa96b41bd5cbd2ed0305f515fcbb367dfa72735679d5502364"}, + {file = "regex-2025.11.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:cc4076a5b4f36d849fd709284b4a3b112326652f3b0466f04002a6c15a0c96c1"}, + {file = "regex-2025.11.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a295ca2bba5c1c885826ce3125fa0b9f702a1be547d821c01d65f199e10c01e2"}, + {file = "regex-2025.11.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b4774ff32f18e0504bfc4e59a3e71e18d83bc1e171a3c8ed75013958a03b2f14"}, + {file = "regex-2025.11.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22e7d1cdfa88ef33a2ae6aa0d707f9255eb286ffbd90045f1088246833223aee"}, + {file = "regex-2025.11.3-cp39-cp39-win32.whl", hash = "sha256:74d04244852ff73b32eeede4f76f51c5bcf44bc3c207bc3e6cf1c5c45b890708"}, + {file = "regex-2025.11.3-cp39-cp39-win_amd64.whl", hash = "sha256:7a50cd39f73faa34ec18d6720ee25ef10c4c1839514186fcda658a06c06057a2"}, + {file = "regex-2025.11.3-cp39-cp39-win_arm64.whl", hash = "sha256:43b4fb020e779ca81c1b5255015fe2b82816c76ec982354534ad9ec09ad7c9e3"}, + {file = "regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01"}, ] [[package]] @@ -2019,7 +2032,6 @@ version = "2.32.5" description = "Python HTTP for Humans." optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, @@ -2041,7 +2053,6 @@ version = "1.0.0" description = "A utility belt for advanced users of python-requests" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -groups = ["dev"] files = [ {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, @@ -2052,167 +2063,126 @@ requests = ">=2.0.1,<3.0.0" [[package]] name = "rpds-py" -version = "0.27.1" +version = "0.30.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "rpds_py-0.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:68afeec26d42ab3b47e541b272166a0b4400313946871cba3ed3a4fc0cab1cef"}, - {file = "rpds_py-0.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74e5b2f7bb6fa38b1b10546d27acbacf2a022a8b5543efb06cfebc72a59c85be"}, - {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9024de74731df54546fab0bfbcdb49fae19159ecaecfc8f37c18d2c7e2c0bd61"}, - {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:31d3ebadefcd73b73928ed0b2fd696f7fefda8629229f81929ac9c1854d0cffb"}, - {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2e7f8f169d775dd9092a1743768d771f1d1300453ddfe6325ae3ab5332b4657"}, - {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d905d16f77eb6ab2e324e09bfa277b4c8e5e6b8a78a3e7ff8f3cdf773b4c013"}, - {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50c946f048209e6362e22576baea09193809f87687a95a8db24e5fbdb307b93a"}, - {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:3deab27804d65cd8289eb814c2c0e807c4b9d9916c9225e363cb0cf875eb67c1"}, - {file = "rpds_py-0.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8b61097f7488de4be8244c89915da8ed212832ccf1e7c7753a25a394bf9b1f10"}, - {file = "rpds_py-0.27.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8a3f29aba6e2d7d90528d3c792555a93497fe6538aa65eb675b44505be747808"}, - {file = "rpds_py-0.27.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd6cd0485b7d347304067153a6dc1d73f7d4fd995a396ef32a24d24b8ac63ac8"}, - {file = "rpds_py-0.27.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6f4461bf931108c9fa226ffb0e257c1b18dc2d44cd72b125bec50ee0ab1248a9"}, - {file = "rpds_py-0.27.1-cp310-cp310-win32.whl", hash = "sha256:ee5422d7fb21f6a00c1901bf6559c49fee13a5159d0288320737bbf6585bd3e4"}, - {file = "rpds_py-0.27.1-cp310-cp310-win_amd64.whl", hash = "sha256:3e039aabf6d5f83c745d5f9a0a381d031e9ed871967c0a5c38d201aca41f3ba1"}, - {file = "rpds_py-0.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:be898f271f851f68b318872ce6ebebbc62f303b654e43bf72683dbdc25b7c881"}, - {file = "rpds_py-0.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:62ac3d4e3e07b58ee0ddecd71d6ce3b1637de2d373501412df395a0ec5f9beb5"}, - {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4708c5c0ceb2d034f9991623631d3d23cb16e65c83736ea020cdbe28d57c0a0e"}, - {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:abfa1171a9952d2e0002aba2ad3780820b00cc3d9c98c6630f2e93271501f66c"}, - {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b507d19f817ebaca79574b16eb2ae412e5c0835542c93fe9983f1e432aca195"}, - {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168b025f8fd8d8d10957405f3fdcef3dc20f5982d398f90851f4abc58c566c52"}, - {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb56c6210ef77caa58e16e8c17d35c63fe3f5b60fd9ba9d424470c3400bcf9ed"}, - {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:d252f2d8ca0195faa707f8eb9368955760880b2b42a8ee16d382bf5dd807f89a"}, - {file = "rpds_py-0.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6e5e54da1e74b91dbc7996b56640f79b195d5925c2b78efaa8c5d53e1d88edde"}, - {file = "rpds_py-0.27.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ffce0481cc6e95e5b3f0a47ee17ffbd234399e6d532f394c8dce320c3b089c21"}, - {file = "rpds_py-0.27.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a205fdfe55c90c2cd8e540ca9ceba65cbe6629b443bc05db1f590a3db8189ff9"}, - {file = "rpds_py-0.27.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:689fb5200a749db0415b092972e8eba85847c23885c8543a8b0f5c009b1a5948"}, - {file = "rpds_py-0.27.1-cp311-cp311-win32.whl", hash = "sha256:3182af66048c00a075010bc7f4860f33913528a4b6fc09094a6e7598e462fe39"}, - {file = "rpds_py-0.27.1-cp311-cp311-win_amd64.whl", hash = "sha256:b4938466c6b257b2f5c4ff98acd8128ec36b5059e5c8f8372d79316b1c36bb15"}, - {file = "rpds_py-0.27.1-cp311-cp311-win_arm64.whl", hash = "sha256:2f57af9b4d0793e53266ee4325535a31ba48e2f875da81a9177c9926dfa60746"}, - {file = "rpds_py-0.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ae2775c1973e3c30316892737b91f9283f9908e3cc7625b9331271eaaed7dc90"}, - {file = "rpds_py-0.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2643400120f55c8a96f7c9d858f7be0c88d383cd4653ae2cf0d0c88f668073e5"}, - {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16323f674c089b0360674a4abd28d5042947d54ba620f72514d69be4ff64845e"}, - {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a1f4814b65eacac94a00fc9a526e3fdafd78e439469644032032d0d63de4881"}, - {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba32c16b064267b22f1850a34051121d423b6f7338a12b9459550eb2096e7ec"}, - {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5c20f33fd10485b80f65e800bbe5f6785af510b9f4056c5a3c612ebc83ba6cb"}, - {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:466bfe65bd932da36ff279ddd92de56b042f2266d752719beb97b08526268ec5"}, - {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:41e532bbdcb57c92ba3be62c42e9f096431b4cf478da9bc3bc6ce5c38ab7ba7a"}, - {file = "rpds_py-0.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f149826d742b406579466283769a8ea448eed82a789af0ed17b0cd5770433444"}, - {file = "rpds_py-0.27.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80c60cfb5310677bd67cb1e85a1e8eb52e12529545441b43e6f14d90b878775a"}, - {file = "rpds_py-0.27.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7ee6521b9baf06085f62ba9c7a3e5becffbc32480d2f1b351559c001c38ce4c1"}, - {file = "rpds_py-0.27.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a512c8263249a9d68cac08b05dd59d2b3f2061d99b322813cbcc14c3c7421998"}, - {file = "rpds_py-0.27.1-cp312-cp312-win32.whl", hash = "sha256:819064fa048ba01b6dadc5116f3ac48610435ac9a0058bbde98e569f9e785c39"}, - {file = "rpds_py-0.27.1-cp312-cp312-win_amd64.whl", hash = "sha256:d9199717881f13c32c4046a15f024971a3b78ad4ea029e8da6b86e5aa9cf4594"}, - {file = "rpds_py-0.27.1-cp312-cp312-win_arm64.whl", hash = "sha256:33aa65b97826a0e885ef6e278fbd934e98cdcfed80b63946025f01e2f5b29502"}, - {file = "rpds_py-0.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e4b9fcfbc021633863a37e92571d6f91851fa656f0180246e84cbd8b3f6b329b"}, - {file = "rpds_py-0.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1441811a96eadca93c517d08df75de45e5ffe68aa3089924f963c782c4b898cf"}, - {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55266dafa22e672f5a4f65019015f90336ed31c6383bd53f5e7826d21a0e0b83"}, - {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78827d7ac08627ea2c8e02c9e5b41180ea5ea1f747e9db0915e3adf36b62dcf"}, - {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae92443798a40a92dc5f0b01d8a7c93adde0c4dc965310a29ae7c64d72b9fad2"}, - {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c46c9dd2403b66a2a3b9720ec4b74d4ab49d4fabf9f03dfdce2d42af913fe8d0"}, - {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418"}, - {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:15d3b4d83582d10c601f481eca29c3f138d44c92187d197aff663a269197c02d"}, - {file = "rpds_py-0.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4ed2e16abbc982a169d30d1a420274a709949e2cbdef119fe2ec9d870b42f274"}, - {file = "rpds_py-0.27.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a75f305c9b013289121ec0f1181931975df78738cdf650093e6b86d74aa7d8dd"}, - {file = "rpds_py-0.27.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:67ce7620704745881a3d4b0ada80ab4d99df390838839921f99e63c474f82cf2"}, - {file = "rpds_py-0.27.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d992ac10eb86d9b6f369647b6a3f412fc0075cfd5d799530e84d335e440a002"}, - {file = "rpds_py-0.27.1-cp313-cp313-win32.whl", hash = "sha256:4f75e4bd8ab8db624e02c8e2fc4063021b58becdbe6df793a8111d9343aec1e3"}, - {file = "rpds_py-0.27.1-cp313-cp313-win_amd64.whl", hash = "sha256:f9025faafc62ed0b75a53e541895ca272815bec18abe2249ff6501c8f2e12b83"}, - {file = "rpds_py-0.27.1-cp313-cp313-win_arm64.whl", hash = "sha256:ed10dc32829e7d222b7d3b93136d25a406ba9788f6a7ebf6809092da1f4d279d"}, - {file = "rpds_py-0.27.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:92022bbbad0d4426e616815b16bc4127f83c9a74940e1ccf3cfe0b387aba0228"}, - {file = "rpds_py-0.27.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:47162fdab9407ec3f160805ac3e154df042e577dd53341745fc7fb3f625e6d92"}, - {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb89bec23fddc489e5d78b550a7b773557c9ab58b7946154a10a6f7a214a48b2"}, - {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e48af21883ded2b3e9eb48cb7880ad8598b31ab752ff3be6457001d78f416723"}, - {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f5b7bd8e219ed50299e58551a410b64daafb5017d54bbe822e003856f06a802"}, - {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08f1e20bccf73b08d12d804d6e1c22ca5530e71659e6673bce31a6bb71c1e73f"}, - {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dc5dceeaefcc96dc192e3a80bbe1d6c410c469e97bdd47494a7d930987f18b2"}, - {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:d76f9cc8665acdc0c9177043746775aa7babbf479b5520b78ae4002d889f5c21"}, - {file = "rpds_py-0.27.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:134fae0e36022edad8290a6661edf40c023562964efea0cc0ec7f5d392d2aaef"}, - {file = "rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:eb11a4f1b2b63337cfd3b4d110af778a59aae51c81d195768e353d8b52f88081"}, - {file = "rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:13e608ac9f50a0ed4faec0e90ece76ae33b34c0e8656e3dceb9a7db994c692cd"}, - {file = "rpds_py-0.27.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dd2135527aa40f061350c3f8f89da2644de26cd73e4de458e79606384f4f68e7"}, - {file = "rpds_py-0.27.1-cp313-cp313t-win32.whl", hash = "sha256:3020724ade63fe320a972e2ffd93b5623227e684315adce194941167fee02688"}, - {file = "rpds_py-0.27.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8ee50c3e41739886606388ba3ab3ee2aae9f35fb23f833091833255a31740797"}, - {file = "rpds_py-0.27.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:acb9aafccaae278f449d9c713b64a9e68662e7799dbd5859e2c6b3c67b56d334"}, - {file = "rpds_py-0.27.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b7fb801aa7f845ddf601c49630deeeccde7ce10065561d92729bfe81bd21fb33"}, - {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe0dd05afb46597b9a2e11c351e5e4283c741237e7f617ffb3252780cca9336a"}, - {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b6dfb0e058adb12d8b1d1b25f686e94ffa65d9995a5157afe99743bf7369d62b"}, - {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed090ccd235f6fa8bb5861684567f0a83e04f52dfc2e5c05f2e4b1309fcf85e7"}, - {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf876e79763eecf3e7356f157540d6a093cef395b65514f17a356f62af6cc136"}, - {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ed005216a51b1d6e2b02a7bd31885fe317e45897de81d86dcce7d74618ffff"}, - {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:ee4308f409a40e50593c7e3bb8cbe0b4d4c66d1674a316324f0c2f5383b486f9"}, - {file = "rpds_py-0.27.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0b08d152555acf1f455154d498ca855618c1378ec810646fcd7c76416ac6dc60"}, - {file = "rpds_py-0.27.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dce51c828941973a5684d458214d3a36fcd28da3e1875d659388f4f9f12cc33e"}, - {file = "rpds_py-0.27.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:c1476d6f29eb81aa4151c9a31219b03f1f798dc43d8af1250a870735516a1212"}, - {file = "rpds_py-0.27.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3ce0cac322b0d69b63c9cdb895ee1b65805ec9ffad37639f291dd79467bee675"}, - {file = "rpds_py-0.27.1-cp314-cp314-win32.whl", hash = "sha256:dfbfac137d2a3d0725758cd141f878bf4329ba25e34979797c89474a89a8a3a3"}, - {file = "rpds_py-0.27.1-cp314-cp314-win_amd64.whl", hash = "sha256:a6e57b0abfe7cc513450fcf529eb486b6e4d3f8aee83e92eb5f1ef848218d456"}, - {file = "rpds_py-0.27.1-cp314-cp314-win_arm64.whl", hash = "sha256:faf8d146f3d476abfee026c4ae3bdd9ca14236ae4e4c310cbd1cf75ba33d24a3"}, - {file = "rpds_py-0.27.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:ba81d2b56b6d4911ce735aad0a1d4495e808b8ee4dc58715998741a26874e7c2"}, - {file = "rpds_py-0.27.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84f7d509870098de0e864cad0102711c1e24e9b1a50ee713b65928adb22269e4"}, - {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e960fc78fecd1100539f14132425e1d5fe44ecb9239f8f27f079962021523e"}, - {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:62f85b665cedab1a503747617393573995dac4600ff51869d69ad2f39eb5e817"}, - {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fed467af29776f6556250c9ed85ea5a4dd121ab56a5f8b206e3e7a4c551e48ec"}, - {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2729615f9d430af0ae6b36cf042cb55c0936408d543fb691e1a9e36648fd35a"}, - {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b207d881a9aef7ba753d69c123a35d96ca7cb808056998f6b9e8747321f03b8"}, - {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:639fd5efec029f99b79ae47e5d7e00ad8a773da899b6309f6786ecaf22948c48"}, - {file = "rpds_py-0.27.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fecc80cb2a90e28af8a9b366edacf33d7a91cbfe4c2c4544ea1246e949cfebeb"}, - {file = "rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42a89282d711711d0a62d6f57d81aa43a1368686c45bc1c46b7f079d55692734"}, - {file = "rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:cf9931f14223de59551ab9d38ed18d92f14f055a5f78c1d8ad6493f735021bbb"}, - {file = "rpds_py-0.27.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f39f58a27cc6e59f432b568ed8429c7e1641324fbe38131de852cd77b2d534b0"}, - {file = "rpds_py-0.27.1-cp314-cp314t-win32.whl", hash = "sha256:d5fa0ee122dc09e23607a28e6d7b150da16c662e66409bbe85230e4c85bb528a"}, - {file = "rpds_py-0.27.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6567d2bb951e21232c2f660c24cf3470bb96de56cdcb3f071a83feeaff8a2772"}, - {file = "rpds_py-0.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c918c65ec2e42c2a78d19f18c553d77319119bf43aa9e2edf7fb78d624355527"}, - {file = "rpds_py-0.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1fea2b1a922c47c51fd07d656324531adc787e415c8b116530a1d29c0516c62d"}, - {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbf94c58e8e0cd6b6f38d8de67acae41b3a515c26169366ab58bdca4a6883bb8"}, - {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2a8fed130ce946d5c585eddc7c8eeef0051f58ac80a8ee43bd17835c144c2cc"}, - {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:037a2361db72ee98d829bc2c5b7cc55598ae0a5e0ec1823a56ea99374cfd73c1"}, - {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5281ed1cc1d49882f9997981c88df1a22e140ab41df19071222f7e5fc4e72125"}, - {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fd50659a069c15eef8aa3d64bbef0d69fd27bb4a50c9ab4f17f83a16cbf8905"}, - {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_31_riscv64.whl", hash = "sha256:c4b676c4ae3921649a15d28ed10025548e9b561ded473aa413af749503c6737e"}, - {file = "rpds_py-0.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:079bc583a26db831a985c5257797b2b5d3affb0386e7ff886256762f82113b5e"}, - {file = "rpds_py-0.27.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4e44099bd522cba71a2c6b97f68e19f40e7d85399de899d66cdb67b32d7cb786"}, - {file = "rpds_py-0.27.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e202e6d4188e53c6661af813b46c37ca2c45e497fc558bacc1a7630ec2695aec"}, - {file = "rpds_py-0.27.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f41f814b8eaa48768d1bb551591f6ba45f87ac76899453e8ccd41dba1289b04b"}, - {file = "rpds_py-0.27.1-cp39-cp39-win32.whl", hash = "sha256:9e71f5a087ead99563c11fdaceee83ee982fd39cf67601f4fd66cb386336ee52"}, - {file = "rpds_py-0.27.1-cp39-cp39-win_amd64.whl", hash = "sha256:71108900c9c3c8590697244b9519017a400d9ba26a36c48381b3f64743a44aab"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7ba22cb9693df986033b91ae1d7a979bc399237d45fccf875b76f62bb9e52ddf"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b640501be9288c77738b5492b3fd3abc4ba95c50c2e41273c8a1459f08298d3"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb08b65b93e0c6dd70aac7f7890a9c0938d5ec71d5cb32d45cf844fb8ae47636"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d7ff07d696a7a38152ebdb8212ca9e5baab56656749f3d6004b34ab726b550b8"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb7c72262deae25366e3b6c0c0ba46007967aea15d1eea746e44ddba8ec58dcc"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b002cab05d6339716b03a4a3a2ce26737f6231d7b523f339fa061d53368c9d8"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23f6b69d1c26c4704fec01311963a41d7de3ee0570a84ebde4d544e5a1859ffc"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:530064db9146b247351f2a0250b8f00b289accea4596a033e94be2389977de71"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b90b0496570bd6b0321724a330d8b545827c4df2034b6ddfc5f5275f55da2ad"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:879b0e14a2da6a1102a3fc8af580fc1ead37e6d6692a781bd8c83da37429b5ab"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:0d807710df3b5faa66c731afa162ea29717ab3be17bdc15f90f2d9f183da4059"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:3adc388fc3afb6540aec081fa59e6e0d3908722771aa1e37ffe22b220a436f0b"}, - {file = "rpds_py-0.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c796c0c1cc68cb08b0284db4229f5af76168172670c74908fdbd4b7d7f515819"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdfe4bb2f9fe7458b7453ad3c33e726d6d1c7c0a72960bcc23800d77384e42df"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:8fabb8fd848a5f75a2324e4a84501ee3a5e3c78d8603f83475441866e60b94a3"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eda8719d598f2f7f3e0f885cba8646644b55a187762bec091fa14a2b819746a9"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c64d07e95606ec402a0a1c511fe003873fa6af630bda59bac77fac8b4318ebc"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93a2ed40de81bcff59aabebb626562d48332f3d028ca2036f1d23cbb52750be4"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:387ce8c44ae94e0ec50532d9cb0edce17311024c9794eb196b90e1058aadeb66"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaf94f812c95b5e60ebaf8bfb1898a7d7cb9c1af5744d4a67fa47796e0465d4e"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:4848ca84d6ded9b58e474dfdbad4b8bfb450344c0551ddc8d958bf4b36aa837c"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2bde09cbcf2248b73c7c323be49b280180ff39fadcfe04e7b6f54a678d02a7cf"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:94c44ee01fd21c9058f124d2d4f0c9dc7634bec93cd4b38eefc385dabe71acbf"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:df8b74962e35c9249425d90144e721eed198e6555a0e22a563d29fe4486b51f6"}, - {file = "rpds_py-0.27.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:dc23e6820e3b40847e2f4a7726462ba0cf53089512abe9ee16318c366494c17a"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa8933159edc50be265ed22b401125c9eebff3171f570258854dbce3ecd55475"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a50431bf02583e21bf273c71b89d710e7a710ad5e39c725b14e685610555926f"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78af06ddc7fe5cc0e967085a9115accee665fb912c22a3f54bad70cc65b05fe6"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:70d0738ef8fee13c003b100c2fbd667ec4f133468109b3472d249231108283a3"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2f6fd8a1cea5bbe599b6e78a6e5ee08db434fc8ffea51ff201c8765679698b3"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8177002868d1426305bb5de1e138161c2ec9eb2d939be38291d7c431c4712df8"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:008b839781d6c9bf3b6a8984d1d8e56f0ec46dc56df61fd669c49b58ae800400"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:a55b9132bb1ade6c734ddd2759c8dc132aa63687d259e725221f106b83a0e485"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a46fdec0083a26415f11d5f236b79fa1291c32aaa4a17684d82f7017a1f818b1"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8a63b640a7845f2bdd232eb0d0a4a2dd939bcdd6c57e6bb134526487f3160ec5"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:7e32721e5d4922deaaf963469d795d5bde6093207c52fec719bd22e5d1bedbc4"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2c426b99a068601b5f4623573df7a7c3d72e87533a2dd2253353a03e7502566c"}, - {file = "rpds_py-0.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4fc9b7fe29478824361ead6e14e4f5aed570d477e06088826537e202d25fe859"}, - {file = "rpds_py-0.27.1.tar.gz", hash = "sha256:26a1c73171d10b7acccbded82bf6a586ab8203601e565badc74bbbf8bc5a10f8"}, +python-versions = ">=3.10" +files = [ + {file = "rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288"}, + {file = "rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221"}, + {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7"}, + {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139"}, + {file = "rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464"}, + {file = "rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169"}, + {file = "rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425"}, + {file = "rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d"}, + {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed"}, + {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85"}, + {file = "rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c"}, + {file = "rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825"}, + {file = "rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229"}, + {file = "rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad"}, + {file = "rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6"}, + {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e"}, + {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394"}, + {file = "rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf"}, + {file = "rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b"}, + {file = "rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e"}, + {file = "rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2"}, + {file = "rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e"}, + {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31"}, + {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95"}, + {file = "rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d"}, + {file = "rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15"}, + {file = "rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1"}, + {file = "rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a"}, + {file = "rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9"}, + {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08"}, + {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27"}, + {file = "rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6"}, + {file = "rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d"}, + {file = "rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0"}, + {file = "rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07"}, + {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f"}, + {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53"}, + {file = "rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed"}, + {file = "rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950"}, + {file = "rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6"}, + {file = "rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb"}, + {file = "rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8"}, + {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856"}, + {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40"}, + {file = "rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0"}, + {file = "rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4"}, + {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e"}, + {file = "rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84"}, ] [[package]] @@ -2221,7 +2191,6 @@ version = "0.12.12" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "ruff-0.12.12-py3-none-linux_armv6l.whl", hash = "sha256:de1c4b916d98ab289818e55ce481e2cacfaad7710b01d1f990c497edf217dafc"}, {file = "ruff-0.12.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7acd6045e87fac75a0b0cdedacf9ab3e1ad9d929d149785903cff9bb69ad9727"}, @@ -2250,7 +2219,6 @@ version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, @@ -2262,7 +2230,6 @@ version = "9.1.2" description = "Retry code until it succeeds" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"}, {file = "tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb"}, @@ -2278,7 +2245,6 @@ version = "0.12.0" description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970"}, {file = "tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16"}, @@ -2352,8 +2318,6 @@ version = "2.3.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" -groups = ["dev"] -markers = "python_version == \"3.10\"" files = [ {file = "tomli-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:88bd15eb972f3664f5ed4b57c1634a97153b4bac4479dcb6a495f41921eb7f45"}, {file = "tomli-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:883b1c0d6398a6a9d29b508c331fa56adbcdff647f6ace4dfca0f50e90dfd0ba"}, @@ -2405,7 +2369,6 @@ version = "4.67.1" description = "Fast, Extensible Progress Meter" optional = false python-versions = ">=3.7" -groups = ["main", "dev"] files = [ {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, @@ -2427,7 +2390,6 @@ version = "4.15.0" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, @@ -2439,7 +2401,6 @@ version = "0.4.2" description = "Runtime typing introspection tools" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, @@ -2450,32 +2411,61 @@ typing-extensions = ">=4.12.0" [[package]] name = "urllib3" -version = "2.6.0" +version = "2.6.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ - {file = "urllib3-2.6.0-py3-none-any.whl", hash = "sha256:c90f7a39f716c572c4e3e58509581ebd83f9b59cced005b7db7ad2d22b0db99f"}, - {file = "urllib3-2.6.0.tar.gz", hash = "sha256:cb9bcef5a4b345d5da5d145dc3e30834f58e8018828cbc724d30b4cb7d4d49f1"}, + {file = "urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd"}, + {file = "urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797"}, ] [package.extras] -brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] +brotli = ["brotli (>=1.2.0)", "brotlicffi (>=1.2.0.0)"] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] +zstd = ["backports-zstd (>=1.0.0)"] + +[[package]] +name = "uuid-utils" +version = "0.12.0" +description = "Drop-in replacement for Python UUID with bindings in Rust" +optional = false +python-versions = ">=3.9" +files = [ + {file = "uuid_utils-0.12.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:3b9b30707659292f207b98f294b0e081f6d77e1fbc760ba5b41331a39045f514"}, + {file = "uuid_utils-0.12.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:add3d820c7ec14ed37317375bea30249699c5d08ff4ae4dbee9fc9bce3bfbf65"}, + {file = "uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b8fce83ecb3b16af29c7809669056c4b6e7cc912cab8c6d07361645de12dd79"}, + {file = "uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec921769afcb905035d785582b0791d02304a7850fbd6ce924c1a8976380dfc6"}, + {file = "uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6f3b060330f5899a92d5c723547dc6a95adef42433e9748f14c66859a7396664"}, + {file = "uuid_utils-0.12.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:908dfef7f0bfcf98d406e5dc570c25d2f2473e49b376de41792b6e96c1d5d291"}, + {file = "uuid_utils-0.12.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c6a24148926bd0ca63e8a2dabf4cc9dc329a62325b3ad6578ecd60fbf926506"}, + {file = "uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:64a91e632669f059ef605f1771d28490b1d310c26198e46f754e8846dddf12f4"}, + {file = "uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:93c082212470bb4603ca3975916c205a9d7ef1443c0acde8fbd1e0f5b36673c7"}, + {file = "uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:431b1fb7283ba974811b22abd365f2726f8f821ab33f0f715be389640e18d039"}, + {file = "uuid_utils-0.12.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2ffd7838c40149100299fa37cbd8bab5ee382372e8e65a148002a37d380df7c8"}, + {file = "uuid_utils-0.12.0-cp39-abi3-win32.whl", hash = "sha256:487f17c0fee6cbc1d8b90fe811874174a9b1b5683bf2251549e302906a50fed3"}, + {file = "uuid_utils-0.12.0-cp39-abi3-win_amd64.whl", hash = "sha256:9598e7c9da40357ae8fffc5d6938b1a7017f09a1acbcc95e14af8c65d48c655a"}, + {file = "uuid_utils-0.12.0-cp39-abi3-win_arm64.whl", hash = "sha256:c9bea7c5b2aa6f57937ebebeee4d4ef2baad10f86f1b97b58a3f6f34c14b4e84"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e2209d361f2996966ab7114f49919eb6aaeabc6041672abbbbf4fdbb8ec1acc0"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d9636bcdbd6cfcad2b549c352b669412d0d1eb09be72044a2f13e498974863cd"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8cd8543a3419251fb78e703ce3b15fdfafe1b7c542cf40caf0775e01db7e7674"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e98db2d8977c052cb307ae1cb5cc37a21715e8d415dbc65863b039397495a013"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8f2bdf5e4ffeb259ef6d15edae92aed60a1d6f07cbfab465d836f6b12b48da8"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c3ec53c0cb15e1835870c139317cc5ec06e35aa22843e3ed7d9c74f23f23898"}, + {file = "uuid_utils-0.12.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:84e5c0eba209356f7f389946a3a47b2cc2effd711b3fc7c7f155ad9f7d45e8a3"}, + {file = "uuid_utils-0.12.0.tar.gz", hash = "sha256:252bd3d311b5d6b7f5dfce7a5857e27bb4458f222586bb439463231e5a9cbd64"}, +] [[package]] name = "virtualenv" -version = "20.35.3" +version = "20.35.4" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" -groups = ["dev"] files = [ - {file = "virtualenv-20.35.3-py3-none-any.whl", hash = "sha256:63d106565078d8c8d0b206d48080f938a8b25361e19432d2c9db40d2899c810a"}, - {file = "virtualenv-20.35.3.tar.gz", hash = "sha256:4f1a845d131133bdff10590489610c98c168ff99dc75d6c96853801f7f67af44"}, + {file = "virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b"}, + {file = "virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c"}, ] [package.dependencies] @@ -2486,7 +2476,7 @@ typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\"" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "werkzeug" @@ -2494,7 +2484,6 @@ version = "3.1.4" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905"}, {file = "werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e"}, @@ -2512,7 +2501,6 @@ version = "1.17.3" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = ">=3.8" -groups = ["main", "dev"] files = [ {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04"}, {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2"}, @@ -2603,7 +2591,6 @@ version = "3.6.0" description = "Python binding for xxHash" optional = false python-versions = ">=3.7" -groups = ["dev"] files = [ {file = "xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71"}, {file = "xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d"}, @@ -2753,14 +2740,13 @@ version = "3.23.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.9" -groups = ["main", "dev"] files = [ {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] @@ -2773,7 +2759,6 @@ version = "0.25.0" description = "Zstandard bindings for Python" optional = false python-versions = ">=3.9" -groups = ["dev"] files = [ {file = "zstandard-0.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e59fdc271772f6686e01e1b3b74537259800f57e24280be3f29c8a0deb1904dd"}, {file = "zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4d441506e9b372386a5271c64125f72d5df6d2a8e8a2a45a0ae09b03cb781ef7"}, @@ -2877,9 +2862,9 @@ files = [ ] [package.extras] -cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and python_version < \"3.14\"", "cffi (>=2.0.0b) ; platform_python_implementation != \"PyPy\" and python_version >= \"3.14\""] +cffi = ["cffi (>=1.17,<2.0)", "cffi (>=2.0.0b)"] [metadata] -lock-version = "2.1" +lock-version = "2.0" python-versions = ">=3.10,<4.0" -content-hash = "bb4ec20d58e29f5d71599357de616571eeae016818d5c246774f0c5bc01d3d0e" +content-hash = "5d2a27e5da32203bea9c89d43e7d1536be7da32fa2b504cf6de1a0749a4ac867" From 59f89e2792b9ca2fddd5a1f369ccc659ad41d8ea Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Wed, 17 Dec 2025 18:43:40 +0100 Subject: [PATCH 03/15] push --- langfuse/_client/client.py | 46 +++++++++++++++++++++----------------- langfuse/model.py | 27 +--------------------- langfuse/types.py | 4 ++-- 3 files changed, 28 insertions(+), 49 deletions(-) diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py index 6ba0e61c1..2ef847f63 100644 --- a/langfuse/_client/client.py +++ b/langfuse/_client/client.py @@ -78,15 +78,19 @@ from langfuse._utils import _get_timestamp from langfuse._utils.parse_error import handle_fern_exception from langfuse._utils.prompt_cache import PromptCache -from langfuse.api.datasets import Dataset, DatasetItem, DatasetStatus -from langfuse.api.ingestion import ScoreBody -from langfuse.api.prompts import ( +from langfuse.api import ( CreatePromptRequest_Chat, CreatePromptRequest_Text, + Dataset, + DatasetItem, + DatasetStatus, + Error, + MapValue, + NotFoundError, Prompt_Chat, Prompt_Text, + ScoreBody, ) -from langfuse.api.utils import Error, NotFoundError from langfuse.batch_evaluation import ( BatchEvaluationResult, BatchEvaluationResumeToken, @@ -112,8 +116,6 @@ ChatMessageDict, ChatMessageWithPlaceholdersDict, ChatPromptClient, - CreateDatasetRunItemRequest, - MapValue, PromptClient, TextPromptClient, ) @@ -2052,15 +2054,15 @@ def create_score( try: new_body = ScoreBody( id=score_id, - sessionId=session_id, - datasetRunId=dataset_run_id, - traceId=trace_id, - observationId=observation_id, + session_id=session_id, + dataset_run_id=dataset_run_id, + trace_id=trace_id, + observation_id=observation_id, name=name, value=value, dataType=data_type, # type: ignore comment=comment, - configId=config_id, + config_id=config_id, environment=self._environment, metadata=metadata, ) @@ -2813,14 +2815,12 @@ async def _process_experiment_item( # creates multiple event loops across different threads dataset_run_item = await asyncio.to_thread( self.api.dataset_run_items.create, - request=CreateDatasetRunItemRequest( - runName=experiment_run_name, - runDescription=experiment_description, - metadata=experiment_metadata, - datasetItemId=item.id, # type: ignore - traceId=trace_id, - observationId=span.id, - ), + run_name=experiment_run_name, + run_description=experiment_description, + metadata=experiment_metadata, + dataset_item_id=item.id, # type: ignore + trace_id=trace_id, + observation_id=span.id, ) dataset_run_id = dataset_run_item.dataset_run_id @@ -3268,7 +3268,7 @@ def create_dataset( try: langfuse_logger.debug(f"Creating datasets {name}") - return self.api.datasets.create( + result = self.api.datasets.create( name=name, description=description, metadata=metadata, @@ -3276,6 +3276,8 @@ def create_dataset( expected_output_schema=expected_output_schema, ) + return cast(Dataset, result) + except Error as e: handle_fern_exception(e) raise e @@ -3327,7 +3329,7 @@ def create_dataset_item( try: langfuse_logger.debug(f"Creating dataset item for dataset {dataset_name}") - return self.api.dataset_items.create( + result = self.api.dataset_items.create( dataset_name=dataset_name, input=input, expected_output=expected_output, @@ -3337,6 +3339,8 @@ def create_dataset_item( status=status, id=id, ) + + return cast(DatasetItem, result) except Error as e: handle_fern_exception(e) raise e diff --git a/langfuse/model.py b/langfuse/model.py index fb13d712e..ab5591603 100644 --- a/langfuse/model.py +++ b/langfuse/model.py @@ -4,32 +4,7 @@ from abc import ABC, abstractmethod from typing import Any, Dict, List, Literal, Optional, Sequence, Tuple, TypedDict, Union -from langfuse.api.commons import ( # noqa: F401 - MapValue, - Observation, - TraceWithFullDetails, -) - -# these imports need to stay here, otherwise imports from our clients wont work -from langfuse.api.dataset_items import ( # noqa: F401 - CreateDatasetItemRequest, - DatasetItem, # noqa: F401 -) - -# noqa: F401 -from langfuse.api.dataset_run_items import ( # noqa: F401 - CreateDatasetRunItemRequest, - DatasetRun, # noqa: F401 -) - -# noqa: F401 -# noqa: F401 -from langfuse.api.datasets import ( # noqa: F401 # noqa: F401 - CreateDatasetRequest, - Dataset, # noqa: F401 - DatasetStatus, -) -from langfuse.api.prompts import Prompt, Prompt_Chat, Prompt_Text +from langfuse.api import Prompt, Prompt_Chat, Prompt_Text from langfuse.logger import langfuse_logger diff --git a/langfuse/types.py b/langfuse/types.py index 99c9b355b..e9f0b1304 100644 --- a/langfuse/types.py +++ b/langfuse/types.py @@ -34,8 +34,8 @@ def my_evaluator(*, output: str, **kwargs) -> Evaluation: from typing_extensions import NotRequired -from langfuse.api import MediaContentType, UsageDetails -from langfuse.model import MapValue, PromptClient +from langfuse.api import MapValue, MediaContentType, UsageDetails +from langfuse.model import PromptClient SpanLevel = Literal["DEBUG", "DEFAULT", "WARNING", "ERROR"] From f5d71547f5d446bcf84e9aa695d2d52c344ac605 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Wed, 17 Dec 2025 19:01:29 +0100 Subject: [PATCH 04/15] push --- langfuse/_client/datasets.py | 13 +++++-------- pyproject.toml | 7 ++----- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/langfuse/_client/datasets.py b/langfuse/_client/datasets.py index 8f1163b72..444e2200d 100644 --- a/langfuse/_client/datasets.py +++ b/langfuse/_client/datasets.py @@ -5,7 +5,6 @@ from opentelemetry.util._decorator import _agnosticcontextmanager from langfuse.api.datasets import ( - CreateDatasetRunItemRequest, Dataset, DatasetItem, DatasetStatus, @@ -131,13 +130,11 @@ def run( ) self.langfuse.api.dataset_run_items.create( - request=CreateDatasetRunItemRequest( - runName=run_name, - datasetItemId=self.id, - traceId=span.trace_id, - metadata=run_metadata, - runDescription=run_description, - ) + run_name=run_name, + dataset_item_id=self.id, + trace_id=span.trace_id, + metadata=run_metadata, + run_description=run_description, ) yield span diff --git a/pyproject.toml b/pyproject.toml index e6d623499..6ae7c8aec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,8 +94,5 @@ module = [ ignore_missing_imports = true [[tool.mypy.overrides]] -module = [ - "langfuse.api.*", -] -ignore_errors = true - +module = "langfuse.api.*" +disable_error_code = ["redundant-cast", "no-untyped-def"] From 5114fa4814f0829b2806cbf3ca5fc3131345925f Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Wed, 17 Dec 2025 19:14:48 +0100 Subject: [PATCH 05/15] push --- langfuse/_client/datasets.py | 2 +- langfuse/_client/resource_manager.py | 2 +- langfuse/_task_manager/media_manager.py | 3 +-- langfuse/_utils/parse_error.py | 6 ++--- langfuse/_utils/serializer.py | 31 +++++++++++++++------ langfuse/batch_evaluation.py | 2 +- tests/test_datasets.py | 6 ++--- tests/test_error_parsing.py | 6 ++--- tests/test_json.py | 2 +- tests/test_prompt.py | 36 ++++++++++++------------- tests/test_prompt_compilation.py | 8 +++--- tests/test_propagate_attributes.py | 2 +- tests/utils.py | 2 +- 13 files changed, 61 insertions(+), 47 deletions(-) diff --git a/langfuse/_client/datasets.py b/langfuse/_client/datasets.py index 444e2200d..2b7e66833 100644 --- a/langfuse/_client/datasets.py +++ b/langfuse/_client/datasets.py @@ -4,7 +4,7 @@ from opentelemetry.util._decorator import _agnosticcontextmanager -from langfuse.api.datasets import ( +from langfuse.api import ( Dataset, DatasetItem, DatasetStatus, diff --git a/langfuse/_client/resource_manager.py b/langfuse/_client/resource_manager.py index 1820807c6..1a74285c3 100644 --- a/langfuse/_client/resource_manager.py +++ b/langfuse/_client/resource_manager.py @@ -42,7 +42,7 @@ from langfuse._utils.environment import get_common_release_envs from langfuse._utils.prompt_cache import PromptCache from langfuse._utils.request import LangfuseClient -from langfuse.api.client import AsyncLangfuseAPI, LangfuseAPI +from langfuse.api import AsyncLangfuseAPI, LangfuseAPI from langfuse.logger import langfuse_logger from langfuse.types import MaskFunction diff --git a/langfuse/_task_manager/media_manager.py b/langfuse/_task_manager/media_manager.py index 388a5c2a1..99312c669 100644 --- a/langfuse/_task_manager/media_manager.py +++ b/langfuse/_task_manager/media_manager.py @@ -10,9 +10,8 @@ from langfuse._client.environment_variables import LANGFUSE_MEDIA_UPLOAD_ENABLED from langfuse._utils import _get_timestamp -from langfuse.api.client import LangfuseAPI +from langfuse.api import LangfuseAPI, MediaContentType from langfuse.api.core import ApiError -from langfuse.api.media import MediaContentType from langfuse.media import LangfuseMedia from .media_upload_queue import UploadMediaJob diff --git a/langfuse/_utils/parse_error.py b/langfuse/_utils/parse_error.py index 86aa6129d..4fd8d6a69 100644 --- a/langfuse/_utils/parse_error.py +++ b/langfuse/_utils/parse_error.py @@ -3,17 +3,17 @@ # our own api errors from langfuse._utils.request import APIError, APIErrors -from langfuse.api.core import ApiError -from langfuse.api.health import ServiceUnavailableError # fern api errors -from langfuse.api.utils import ( +from langfuse.api import ( AccessDeniedError, Error, MethodNotAllowedError, NotFoundError, + ServiceUnavailableError, UnauthorizedError, ) +from langfuse.api.core import ApiError SUPPORT_URL = "https://langfuse.com/support" API_DOCS_URL = "https://api.reference.langfuse.com" diff --git a/langfuse/_utils/serializer.py b/langfuse/_utils/serializer.py index 1350ea00c..c2dad3312 100644 --- a/langfuse/_utils/serializer.py +++ b/langfuse/_utils/serializer.py @@ -1,5 +1,6 @@ """@private""" +import datetime as dt import enum import math from asyncio import Queue @@ -14,7 +15,6 @@ from pydantic import BaseModel -from langfuse.api.core import pydantic_utilities, serialize_datetime from langfuse.media import LangfuseMedia # Attempt to import Serializable @@ -98,17 +98,13 @@ def default(self, obj: Any) -> Any: return obj.isoformat() if isinstance(obj, BaseModel): - obj.model_rebuild() if pydantic_utilities.IS_PYDANTIC_V2 else obj.update_forward_refs() # This method forces the OpenAI model to instantiate its serializer to avoid errors when serializing + obj.model_rebuild() # For LlamaIndex models, we need to rebuild the raw model as well if they include OpenAI models if isinstance(raw := getattr(obj, "raw", None), BaseModel): - raw.model_rebuild() if pydantic_utilities.IS_PYDANTIC_V2 else raw.update_forward_refs() + raw.model_rebuild() - return ( - obj.model_dump() - if pydantic_utilities.IS_PYDANTIC_V2 - else obj.dict() - ) + return obj.model_dump() if isinstance(obj, Path): return str(obj) @@ -188,3 +184,22 @@ def is_js_safe_integer(value: int) -> bool: min_safe_int = -(2**53) + 1 return min_safe_int <= value <= max_safe_int + + +def serialize_datetime(v: dt.datetime) -> str: + def _serialize_zoned_datetime(v: dt.datetime) -> str: + if v.tzinfo is not None and v.tzinfo.tzname(None) == dt.timezone.utc.tzname( + None + ): + # UTC is a special case where we use "Z" at the end instead of "+00:00" + return v.isoformat().replace("+00:00", "Z") + else: + # Delegate to the typical +/- offset format + return v.isoformat() + + if v.tzinfo is not None: + return _serialize_zoned_datetime(v) + else: + local_tz = dt.datetime.now().astimezone().tzinfo + localized_dt = v.replace(tzinfo=local_tz) + return _serialize_zoned_datetime(localized_dt) diff --git a/langfuse/batch_evaluation.py b/langfuse/batch_evaluation.py index 391334b66..cb074af42 100644 --- a/langfuse/batch_evaluation.py +++ b/langfuse/batch_evaluation.py @@ -22,7 +22,7 @@ Union, ) -from langfuse.api.commons import ( +from langfuse.api import ( ObservationsView, TraceWithFullDetails, ) diff --git a/tests/test_datasets.py b/tests/test_datasets.py index c1b81868d..3b18a5a66 100644 --- a/tests/test_datasets.py +++ b/tests/test_datasets.py @@ -7,8 +7,8 @@ from langchain_openai import OpenAI from langfuse import Langfuse, observe -from langfuse.api.resources.commons.types.dataset_status import DatasetStatus -from langfuse.api.resources.commons.types.observation import Observation +from langfuse.api import DatasetStatus +from langfuse.api import Observation from langfuse.langchain import CallbackHandler from tests.utils import create_uuid, get_api @@ -220,7 +220,7 @@ def test_get_dataset_runs(): langfuse.flush() time.sleep(1) # Give API time to process - runs = langfuse.api.datasets.get_runs(dataset_name) + runs = langfuse.api assert len(runs.data) == 2 assert runs.data[0].name == run_name_2 diff --git a/tests/test_error_parsing.py b/tests/test_error_parsing.py index db53f3d4d..36a7decbf 100644 --- a/tests/test_error_parsing.py +++ b/tests/test_error_parsing.py @@ -5,14 +5,14 @@ generate_error_message_fern, ) from langfuse._utils.request import APIError, APIErrors -from langfuse.api.core import ApiError -from langfuse.api.resources.commons.errors import ( +from langfuse.api import ( AccessDeniedError, MethodNotAllowedError, NotFoundError, + ServiceUnavailableError, UnauthorizedError, ) -from langfuse.api.resources.health.errors import ServiceUnavailableError +from langfuse.api.core import ApiError def test_generate_error_message_api_error(): diff --git a/tests/test_json.py b/tests/test_json.py index 26b6919fa..1f7ef6ece 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -12,7 +12,7 @@ import langfuse from langfuse._utils.serializer import EventSerializer -from langfuse.api.resources.commons.types.observation_level import ObservationLevel +from langfuse.api import ObservationLevel class TestModel(BaseModel): diff --git a/tests/test_prompt.py b/tests/test_prompt.py index 6ba5ab85a..a4466adb3 100644 --- a/tests/test_prompt.py +++ b/tests/test_prompt.py @@ -10,8 +10,8 @@ PromptCache, PromptCacheItem, ) -from langfuse.api.resources.commons.errors.not_found_error import NotFoundError -from langfuse.api.resources.prompts import Prompt_Chat, Prompt_Text +from langfuse.api import NotFoundError +from langfuse.api import Prompt_Chat, Prompt_Text from langfuse.model import ChatPromptClient, TextPromptClient from tests.utils import create_uuid, get_api @@ -312,7 +312,7 @@ def test_compile_with_placeholders( variables, placeholders, expected_len, expected_contents ) -> None: """Test compile_with_placeholders with different variable/placeholder combinations.""" - from langfuse.api.resources.prompts import Prompt_Chat + from langfuse.api import Prompt_Chat from langfuse.model import ChatPromptClient mock_prompt = Prompt_Chat( @@ -706,7 +706,7 @@ def test_get_fresh_prompt(langfuse): tags=[], ) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result = langfuse.get_prompt(prompt_name, fallback="fallback") @@ -734,7 +734,7 @@ def test_throw_if_name_unspecified(langfuse): def test_throw_when_failing_fetch_and_no_cache(langfuse): prompt_name = "failing_fetch_and_no_cache" - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.side_effect = Exception("Prompt not found") with pytest.raises(Exception) as exc_info: @@ -755,7 +755,7 @@ def test_using_custom_prompt_timeouts(langfuse): tags=[], ) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result = langfuse.get_prompt( @@ -796,7 +796,7 @@ def test_get_valid_cached_prompt(langfuse): ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name, fallback="fallback") @@ -822,7 +822,7 @@ def test_get_valid_cached_chat_prompt_by_label(langfuse): ) prompt_client = ChatPromptClient(prompt) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name, label="test") @@ -848,7 +848,7 @@ def test_get_valid_cached_chat_prompt_by_version(langfuse): ) prompt_client = ChatPromptClient(prompt) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name, version=1) @@ -874,7 +874,7 @@ def test_get_valid_cached_production_chat_prompt(langfuse): ) prompt_client = ChatPromptClient(prompt) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name) @@ -900,7 +900,7 @@ def test_get_valid_cached_chat_prompt(langfuse): ) prompt_client = ChatPromptClient(prompt) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name) @@ -930,7 +930,7 @@ def test_get_fresh_prompt_when_expired_cache_custom_ttl(mock_time, langfuse: Lan ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name, cache_ttl_seconds=ttl_seconds) @@ -995,7 +995,7 @@ def test_disable_caching_when_ttl_zero(mock_time, langfuse: Langfuse): tags=[], ) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.side_effect = [prompt1, prompt2, prompt3] # First call @@ -1037,7 +1037,7 @@ def test_get_stale_prompt_when_expired_cache_default_ttl(mock_time, langfuse: La ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name) @@ -1099,7 +1099,7 @@ def test_get_fresh_prompt_when_expired_cache_default_ttl(mock_time, langfuse: La ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name) @@ -1143,7 +1143,7 @@ def test_get_expired_prompt_when_failing_fetch(mock_time, langfuse: Langfuse): ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name) @@ -1187,7 +1187,7 @@ def test_evict_prompt_cache_entry_when_refresh_returns_not_found( prompt_client = TextPromptClient(prompt) cache_key = PromptCache.generate_cache_key(prompt_name, version=None, label=None) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt initial_result = langfuse.get_prompt( @@ -1244,7 +1244,7 @@ def test_get_fresh_prompt_when_version_changes(langfuse: Langfuse): ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api.prompts.get + mock_server_call = langfuse.api mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name, version=1) diff --git a/tests/test_prompt_compilation.py b/tests/test_prompt_compilation.py index 039556c5d..1b96a14dd 100644 --- a/tests/test_prompt_compilation.py +++ b/tests/test_prompt_compilation.py @@ -1,7 +1,7 @@ import pytest from langchain_core.prompts import ChatPromptTemplate, PromptTemplate -from langfuse.api.resources.prompts import ChatMessage, Prompt_Chat +from langfuse.api import ChatMessage, Prompt_Chat from langfuse.model import ( ChatPromptClient, Prompt_Text, @@ -735,7 +735,7 @@ def test_chat_prompt_with_json_variables(self): def test_chat_prompt_with_placeholders_langchain(self): """Test that chat prompts with placeholders work correctly with Langchain.""" - from langfuse.api.resources.prompts import Prompt_Chat + from langfuse.api import Prompt_Chat chat_messages = [ ChatMessage( @@ -804,7 +804,7 @@ def test_chat_prompt_with_placeholders_langchain(self): def test_get_langchain_prompt_with_unresolved_placeholders(self): """Test that unresolved placeholders become MessagesPlaceholder objects.""" - from langfuse.api.resources.prompts import Prompt_Chat + from langfuse.api import Prompt_Chat from langfuse.model import ChatPromptClient chat_messages = [ @@ -854,7 +854,7 @@ def test_get_langchain_prompt_with_unresolved_placeholders(self): def test_tool_calls_preservation_in_message_placeholder(): """Test that tool calls are preserved when compiling message placeholders.""" - from langfuse.api.resources.prompts import Prompt_Chat + from langfuse.api import Prompt_Chat chat_messages = [ {"role": "system", "content": "You are a helpful assistant."}, diff --git a/tests/test_propagate_attributes.py b/tests/test_propagate_attributes.py index 83c88e48a..c4a2799e2 100644 --- a/tests/test_propagate_attributes.py +++ b/tests/test_propagate_attributes.py @@ -2446,7 +2446,7 @@ def test_experiment_attributes_propagate_with_dataset( # Mock the async API to create dataset run items async def mock_create_dataset_run_item(*args, **kwargs): - from langfuse.api.resources.dataset_run_items.types import DatasetRunItem + from langfuse.api import DatasetRunItem request = kwargs.get("request") return DatasetRunItem( diff --git a/tests/utils.py b/tests/utils.py index 1e3ee28a3..f42767983 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -9,7 +9,7 @@ except ImportError: import pydantic # type: ignore -from langfuse.api.client import LangfuseAPI +from langfuse.api import LangfuseAPI def create_uuid(): From a7c98a2b5d70bce81ce9eb93845f8ae14550edcf Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 22 Dec 2025 11:39:15 +0100 Subject: [PATCH 06/15] push --- langfuse/_client/client.py | 11 +- langfuse/api/.fern/metadata.json | 2 +- langfuse/api/__init__.py | 32 +- langfuse/api/client.py | 42 ++ langfuse/api/metrics_v2/__init__.py | 40 ++ langfuse/api/metrics_v2/client.py | 422 ++++++++++++ langfuse/api/metrics_v2/raw_client.py | 530 +++++++++++++++ langfuse/api/metrics_v2/types/__init__.py | 40 ++ .../metrics_v2/types/metrics_v2response.py | 26 + langfuse/api/observations_v2/__init__.py | 43 ++ langfuse/api/observations_v2/client.py | 504 ++++++++++++++ langfuse/api/observations_v2/raw_client.py | 623 ++++++++++++++++++ .../api/observations_v2/types/__init__.py | 44 ++ .../types/observations_v2meta.py | 28 + .../types/observations_v2response.py | 34 + langfuse/api/prompts/__init__.py | 18 +- langfuse/api/prompts/client.py | 24 +- langfuse/api/prompts/types/__init__.py | 26 +- .../types/chat_message_with_placeholders.py | 48 +- .../types/create_chat_prompt_request.py | 2 + .../prompts/types/create_chat_prompt_type.py | 5 + .../prompts/types/create_prompt_request.py | 61 +- .../types/create_text_prompt_request.py | 2 + .../prompts/types/create_text_prompt_type.py | 5 + tests/test_prompt.py | 33 +- 25 files changed, 2462 insertions(+), 183 deletions(-) create mode 100644 langfuse/api/metrics_v2/__init__.py create mode 100644 langfuse/api/metrics_v2/client.py create mode 100644 langfuse/api/metrics_v2/raw_client.py create mode 100644 langfuse/api/metrics_v2/types/__init__.py create mode 100644 langfuse/api/metrics_v2/types/metrics_v2response.py create mode 100644 langfuse/api/observations_v2/__init__.py create mode 100644 langfuse/api/observations_v2/client.py create mode 100644 langfuse/api/observations_v2/raw_client.py create mode 100644 langfuse/api/observations_v2/types/__init__.py create mode 100644 langfuse/api/observations_v2/types/observations_v2meta.py create mode 100644 langfuse/api/observations_v2/types/observations_v2response.py create mode 100644 langfuse/api/prompts/types/create_chat_prompt_type.py create mode 100644 langfuse/api/prompts/types/create_text_prompt_type.py diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py index 2ef847f63..abb6b2640 100644 --- a/langfuse/_client/client.py +++ b/langfuse/_client/client.py @@ -79,8 +79,8 @@ from langfuse._utils.parse_error import handle_fern_exception from langfuse._utils.prompt_cache import PromptCache from langfuse.api import ( - CreatePromptRequest_Chat, - CreatePromptRequest_Text, + CreateChatPromptRequest, + CreateTextPromptRequest, Dataset, DatasetItem, DatasetStatus, @@ -3702,8 +3702,8 @@ def create_prompt( raise ValueError( "For 'chat' type, 'prompt' must be a list of chat messages with role and content attributes." ) - request: Union[CreatePromptRequest_Chat, CreatePromptRequest_Text] = ( - CreatePromptRequest_Chat( + request: Union[CreateChatPromptRequest, CreateTextPromptRequest] = ( + CreateChatPromptRequest( name=name, prompt=cast(Any, prompt), labels=labels, @@ -3723,14 +3723,13 @@ def create_prompt( if not isinstance(prompt, str): raise ValueError("For 'text' type, 'prompt' must be a string.") - request = CreatePromptRequest_Text( + request = CreateTextPromptRequest( name=name, prompt=prompt, labels=labels, tags=tags, config=config or {}, commit_message=commit_message, - type="text", ) server_prompt = self.api.prompts.create(request=request) diff --git a/langfuse/api/.fern/metadata.json b/langfuse/api/.fern/metadata.json index 3e02d7184..e1ced29c9 100644 --- a/langfuse/api/.fern/metadata.json +++ b/langfuse/api/.fern/metadata.json @@ -1,5 +1,5 @@ { - "cliVersion": "3.24.3", + "cliVersion": "3.30.3", "generatorName": "fernapi/fern-python-sdk", "generatorVersion": "4.46.2", "generatorConfig": { diff --git a/langfuse/api/__init__.py b/langfuse/api/__init__.py index ed4ae1708..dc72246e3 100644 --- a/langfuse/api/__init__.py +++ b/langfuse/api/__init__.py @@ -19,8 +19,10 @@ llm_connections, media, metrics, + metrics_v2, models, observations, + observations_v2, opentelemetry, organizations, projects, @@ -189,8 +191,10 @@ PatchMediaBody, ) from .metrics import MetricsResponse + from .metrics_v2 import MetricsV2Response from .models import CreateModelRequest, PaginatedModels from .observations import Observations, ObservationsViews + from .observations_v2 import ObservationsV2Meta, ObservationsV2Response from .opentelemetry import ( OtelAttribute, OtelAttributeValue, @@ -226,14 +230,12 @@ BasePrompt, ChatMessage, ChatMessageWithPlaceholders, - ChatMessageWithPlaceholders_Chatmessage, - ChatMessageWithPlaceholders_Placeholder, ChatPrompt, CreateChatPromptRequest, + CreateChatPromptType, CreatePromptRequest, - CreatePromptRequest_Chat, - CreatePromptRequest_Text, CreateTextPromptRequest, + CreateTextPromptType, PlaceholderMessage, Prompt, PromptMeta, @@ -312,8 +314,6 @@ "CategoricalScoreV1": ".commons", "ChatMessage": ".prompts", "ChatMessageWithPlaceholders": ".prompts", - "ChatMessageWithPlaceholders_Chatmessage": ".prompts", - "ChatMessageWithPlaceholders_Placeholder": ".prompts", "ChatPrompt": ".prompts", "Comment": ".commons", "CommentObjectType": ".commons", @@ -323,6 +323,7 @@ "CreateAnnotationQueueRequest": ".annotation_queues", "CreateBlobStorageIntegrationRequest": ".blob_storage_integrations", "CreateChatPromptRequest": ".prompts", + "CreateChatPromptType": ".prompts", "CreateCommentRequest": ".comments", "CreateCommentResponse": ".comments", "CreateDatasetItemRequest": ".dataset_items", @@ -335,8 +336,6 @@ "CreateModelRequest": ".models", "CreateObservationEvent": ".ingestion", "CreatePromptRequest": ".prompts", - "CreatePromptRequest_Chat": ".prompts", - "CreatePromptRequest_Text": ".prompts", "CreateScoreConfigRequest": ".score_configs", "CreateScoreRequest": ".score", "CreateScoreResponse": ".score", @@ -344,6 +343,7 @@ "CreateSpanBody": ".ingestion", "CreateSpanEvent": ".ingestion", "CreateTextPromptRequest": ".prompts", + "CreateTextPromptType": ".prompts", "Dataset": ".commons", "DatasetItem": ".commons", "DatasetRun": ".commons", @@ -400,6 +400,7 @@ "MembershipsResponse": ".organizations", "MethodNotAllowedError": ".commons", "MetricsResponse": ".metrics", + "MetricsV2Response": ".metrics_v2", "Model": ".commons", "ModelPrice": ".commons", "ModelUsageUnit": ".commons", @@ -411,6 +412,8 @@ "ObservationLevel": ".commons", "ObservationType": ".ingestion", "Observations": ".observations", + "ObservationsV2Meta": ".observations_v2", + "ObservationsV2Response": ".observations_v2", "ObservationsView": ".commons", "ObservationsViews": ".observations", "OpenAiCompletionUsageSchema": ".ingestion", @@ -517,8 +520,10 @@ "llm_connections": ".llm_connections", "media": ".media", "metrics": ".metrics", + "metrics_v2": ".metrics_v2", "models": ".models", "observations": ".observations", + "observations_v2": ".observations_v2", "opentelemetry": ".opentelemetry", "organizations": ".organizations", "projects": ".projects", @@ -592,8 +597,6 @@ def __dir__(): "CategoricalScoreV1", "ChatMessage", "ChatMessageWithPlaceholders", - "ChatMessageWithPlaceholders_Chatmessage", - "ChatMessageWithPlaceholders_Placeholder", "ChatPrompt", "Comment", "CommentObjectType", @@ -603,6 +606,7 @@ def __dir__(): "CreateAnnotationQueueRequest", "CreateBlobStorageIntegrationRequest", "CreateChatPromptRequest", + "CreateChatPromptType", "CreateCommentRequest", "CreateCommentResponse", "CreateDatasetItemRequest", @@ -615,8 +619,6 @@ def __dir__(): "CreateModelRequest", "CreateObservationEvent", "CreatePromptRequest", - "CreatePromptRequest_Chat", - "CreatePromptRequest_Text", "CreateScoreConfigRequest", "CreateScoreRequest", "CreateScoreResponse", @@ -624,6 +626,7 @@ def __dir__(): "CreateSpanBody", "CreateSpanEvent", "CreateTextPromptRequest", + "CreateTextPromptType", "Dataset", "DatasetItem", "DatasetRun", @@ -680,6 +683,7 @@ def __dir__(): "MembershipsResponse", "MethodNotAllowedError", "MetricsResponse", + "MetricsV2Response", "Model", "ModelPrice", "ModelUsageUnit", @@ -691,6 +695,8 @@ def __dir__(): "ObservationLevel", "ObservationType", "Observations", + "ObservationsV2Meta", + "ObservationsV2Response", "ObservationsView", "ObservationsViews", "OpenAiCompletionUsageSchema", @@ -797,8 +803,10 @@ def __dir__(): "llm_connections", "media", "metrics", + "metrics_v2", "models", "observations", + "observations_v2", "opentelemetry", "organizations", "projects", diff --git a/langfuse/api/client.py b/langfuse/api/client.py index 14c1ae54f..041f214b9 100644 --- a/langfuse/api/client.py +++ b/langfuse/api/client.py @@ -28,8 +28,10 @@ from .llm_connections.client import AsyncLlmConnectionsClient, LlmConnectionsClient from .media.client import AsyncMediaClient, MediaClient from .metrics.client import AsyncMetricsClient, MetricsClient + from .metrics_v2.client import AsyncMetricsV2Client, MetricsV2Client from .models.client import AsyncModelsClient, ModelsClient from .observations.client import AsyncObservationsClient, ObservationsClient + from .observations_v2.client import AsyncObservationsV2Client, ObservationsV2Client from .opentelemetry.client import AsyncOpentelemetryClient, OpentelemetryClient from .organizations.client import AsyncOrganizationsClient, OrganizationsClient from .projects.client import AsyncProjectsClient, ProjectsClient @@ -133,8 +135,10 @@ def __init__( self._ingestion: typing.Optional[IngestionClient] = None self._llm_connections: typing.Optional[LlmConnectionsClient] = None self._media: typing.Optional[MediaClient] = None + self._metrics_v2: typing.Optional[MetricsV2Client] = None self._metrics: typing.Optional[MetricsClient] = None self._models: typing.Optional[ModelsClient] = None + self._observations_v2: typing.Optional[ObservationsV2Client] = None self._observations: typing.Optional[ObservationsClient] = None self._opentelemetry: typing.Optional[OpentelemetryClient] = None self._organizations: typing.Optional[OrganizationsClient] = None @@ -238,6 +242,14 @@ def media(self): self._media = MediaClient(client_wrapper=self._client_wrapper) return self._media + @property + def metrics_v2(self): + if self._metrics_v2 is None: + from .metrics_v2.client import MetricsV2Client # noqa: E402 + + self._metrics_v2 = MetricsV2Client(client_wrapper=self._client_wrapper) + return self._metrics_v2 + @property def metrics(self): if self._metrics is None: @@ -254,6 +266,16 @@ def models(self): self._models = ModelsClient(client_wrapper=self._client_wrapper) return self._models + @property + def observations_v2(self): + if self._observations_v2 is None: + from .observations_v2.client import ObservationsV2Client # noqa: E402 + + self._observations_v2 = ObservationsV2Client( + client_wrapper=self._client_wrapper + ) + return self._observations_v2 + @property def observations(self): if self._observations is None: @@ -449,8 +471,10 @@ def __init__( self._ingestion: typing.Optional[AsyncIngestionClient] = None self._llm_connections: typing.Optional[AsyncLlmConnectionsClient] = None self._media: typing.Optional[AsyncMediaClient] = None + self._metrics_v2: typing.Optional[AsyncMetricsV2Client] = None self._metrics: typing.Optional[AsyncMetricsClient] = None self._models: typing.Optional[AsyncModelsClient] = None + self._observations_v2: typing.Optional[AsyncObservationsV2Client] = None self._observations: typing.Optional[AsyncObservationsClient] = None self._opentelemetry: typing.Optional[AsyncOpentelemetryClient] = None self._organizations: typing.Optional[AsyncOrganizationsClient] = None @@ -556,6 +580,14 @@ def media(self): self._media = AsyncMediaClient(client_wrapper=self._client_wrapper) return self._media + @property + def metrics_v2(self): + if self._metrics_v2 is None: + from .metrics_v2.client import AsyncMetricsV2Client # noqa: E402 + + self._metrics_v2 = AsyncMetricsV2Client(client_wrapper=self._client_wrapper) + return self._metrics_v2 + @property def metrics(self): if self._metrics is None: @@ -572,6 +604,16 @@ def models(self): self._models = AsyncModelsClient(client_wrapper=self._client_wrapper) return self._models + @property + def observations_v2(self): + if self._observations_v2 is None: + from .observations_v2.client import AsyncObservationsV2Client # noqa: E402 + + self._observations_v2 = AsyncObservationsV2Client( + client_wrapper=self._client_wrapper + ) + return self._observations_v2 + @property def observations(self): if self._observations is None: diff --git a/langfuse/api/metrics_v2/__init__.py b/langfuse/api/metrics_v2/__init__.py new file mode 100644 index 000000000..0421785de --- /dev/null +++ b/langfuse/api/metrics_v2/__init__.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import MetricsV2Response +_dynamic_imports: typing.Dict[str, str] = {"MetricsV2Response": ".types"} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["MetricsV2Response"] diff --git a/langfuse/api/metrics_v2/client.py b/langfuse/api/metrics_v2/client.py new file mode 100644 index 000000000..d6c05914c --- /dev/null +++ b/langfuse/api/metrics_v2/client.py @@ -0,0 +1,422 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawMetricsV2Client, RawMetricsV2Client +from .types.metrics_v2response import MetricsV2Response + + +class MetricsV2Client: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawMetricsV2Client(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawMetricsV2Client: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawMetricsV2Client + """ + return self._raw_client + + def metrics( + self, *, query: str, request_options: typing.Optional[RequestOptions] = None + ) -> MetricsV2Response: + """ + Get metrics from the Langfuse project using a query object. V2 endpoint with optimized performance. + + ## V2 Differences + - Supports `observations`, `scores-numeric`, and `scores-categorical` views only (traces view not supported) + - Direct access to tags and release fields on observations + - Backwards-compatible: traceName, traceRelease, traceVersion dimensions are still available on observations view + - High cardinality dimensions are not supported and will return a 400 error (see below) + + For more details, see the [Metrics API documentation](https://langfuse.com/docs/metrics/features/metrics-api). + + ## Available Views + + ### observations + Query observation-level data (spans, generations, events). + + **Dimensions:** + - `environment` - Deployment environment (e.g., production, staging) + - `type` - Type of observation (SPAN, GENERATION, EVENT) + - `name` - Name of the observation + - `level` - Logging level of the observation + - `version` - Version of the observation + - `tags` - User-defined tags + - `release` - Release version + - `traceName` - Name of the parent trace (backwards-compatible) + - `traceRelease` - Release version of the parent trace (backwards-compatible, maps to release) + - `traceVersion` - Version of the parent trace (backwards-compatible, maps to version) + - `providedModelName` - Name of the model used + - `promptName` - Name of the prompt used + - `promptVersion` - Version of the prompt used + - `startTimeMonth` - Month of start_time in YYYY-MM format + + **Measures:** + - `count` - Total number of observations + - `latency` - Observation latency (milliseconds) + - `streamingLatency` - Generation latency from completion start to end (milliseconds) + - `inputTokens` - Sum of input tokens consumed + - `outputTokens` - Sum of output tokens produced + - `totalTokens` - Sum of all tokens consumed + - `outputTokensPerSecond` - Output tokens per second + - `tokensPerSecond` - Total tokens per second + - `inputCost` - Input cost (USD) + - `outputCost` - Output cost (USD) + - `totalCost` - Total cost (USD) + - `timeToFirstToken` - Time to first token (milliseconds) + - `countScores` - Number of scores attached to the observation + + ### scores-numeric + Query numeric and boolean score data. + + **Dimensions:** + - `environment` - Deployment environment + - `name` - Name of the score (e.g., accuracy, toxicity) + - `source` - Origin of the score (API, ANNOTATION, EVAL) + - `dataType` - Data type (NUMERIC, BOOLEAN) + - `configId` - Identifier of the score config + - `timestampMonth` - Month in YYYY-MM format + - `timestampDay` - Day in YYYY-MM-DD format + - `value` - Numeric value of the score + - `traceName` - Name of the parent trace + - `tags` - Tags + - `traceRelease` - Release version + - `traceVersion` - Version + - `observationName` - Name of the associated observation + - `observationModelName` - Model name of the associated observation + - `observationPromptName` - Prompt name of the associated observation + - `observationPromptVersion` - Prompt version of the associated observation + + **Measures:** + - `count` - Total number of scores + - `value` - Score value (for aggregations) + + ### scores-categorical + Query categorical score data. Same dimensions as scores-numeric except uses `stringValue` instead of `value`. + + **Measures:** + - `count` - Total number of scores + + ## High Cardinality Dimensions + The following dimensions cannot be used as grouping dimensions in v2 metrics API as they can cause performance issues. + Use them in filters instead. + + **observations view:** + - `id` - Use traceId filter to narrow down results + - `traceId` - Use traceId filter instead + - `userId` - Use userId filter instead + - `sessionId` - Use sessionId filter instead + - `parentObservationId` - Use parentObservationId filter instead + + **scores-numeric / scores-categorical views:** + - `id` - Use specific filters to narrow down results + - `traceId` - Use traceId filter instead + - `userId` - Use userId filter instead + - `sessionId` - Use sessionId filter instead + - `observationId` - Use observationId filter instead + + ## Aggregations + Available aggregation functions: `sum`, `avg`, `count`, `max`, `min`, `p50`, `p75`, `p90`, `p95`, `p99`, `histogram` + + ## Time Granularities + Available granularities for timeDimension: `auto`, `minute`, `hour`, `day`, `week`, `month` + - `auto` bins the data into approximately 50 buckets based on the time range + + Parameters + ---------- + query : str + JSON string containing the query parameters with the following structure: + ```json + { + "view": string, // Required. One of "observations", "scores-numeric", "scores-categorical" + "dimensions": [ // Optional. Default: [] + { + "field": string // Field to group by (see available dimensions above) + } + ], + "metrics": [ // Required. At least one metric must be provided + { + "measure": string, // What to measure (see available measures above) + "aggregation": string // How to aggregate: "sum", "avg", "count", "max", "min", "p50", "p75", "p90", "p95", "p99", "histogram" + } + ], + "filters": [ // Optional. Default: [] + { + "column": string, // Column to filter on (any dimension field) + "operator": string, // Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject/numberObject: same as string/number with required "key" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Value to compare against + "type": string, // Data type: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "key": string // Required only for stringObject/numberObject types (e.g., metadata filtering) + } + ], + "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time + "granularity": string // One of "auto", "minute", "hour", "day", "week", "month" + }, + "fromTimestamp": string, // Required. ISO datetime string for start of time range + "toTimestamp": string, // Required. ISO datetime string for end of time range (must be after fromTimestamp) + "orderBy": [ // Optional. Default: null + { + "field": string, // Field to order by (dimension or metric alias) + "direction": string // "asc" or "desc" + } + ], + "config": { // Optional. Query-specific configuration + "bins": number, // Optional. Number of bins for histogram aggregation (1-100), default: 10 + "row_limit": number // Optional. Maximum number of rows to return (1-1000), default: 100 + } + } + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MetricsV2Response + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.metrics_v2.metrics( + query="query", + ) + """ + _response = self._raw_client.metrics( + query=query, request_options=request_options + ) + return _response.data + + +class AsyncMetricsV2Client: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawMetricsV2Client(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawMetricsV2Client: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawMetricsV2Client + """ + return self._raw_client + + async def metrics( + self, *, query: str, request_options: typing.Optional[RequestOptions] = None + ) -> MetricsV2Response: + """ + Get metrics from the Langfuse project using a query object. V2 endpoint with optimized performance. + + ## V2 Differences + - Supports `observations`, `scores-numeric`, and `scores-categorical` views only (traces view not supported) + - Direct access to tags and release fields on observations + - Backwards-compatible: traceName, traceRelease, traceVersion dimensions are still available on observations view + - High cardinality dimensions are not supported and will return a 400 error (see below) + + For more details, see the [Metrics API documentation](https://langfuse.com/docs/metrics/features/metrics-api). + + ## Available Views + + ### observations + Query observation-level data (spans, generations, events). + + **Dimensions:** + - `environment` - Deployment environment (e.g., production, staging) + - `type` - Type of observation (SPAN, GENERATION, EVENT) + - `name` - Name of the observation + - `level` - Logging level of the observation + - `version` - Version of the observation + - `tags` - User-defined tags + - `release` - Release version + - `traceName` - Name of the parent trace (backwards-compatible) + - `traceRelease` - Release version of the parent trace (backwards-compatible, maps to release) + - `traceVersion` - Version of the parent trace (backwards-compatible, maps to version) + - `providedModelName` - Name of the model used + - `promptName` - Name of the prompt used + - `promptVersion` - Version of the prompt used + - `startTimeMonth` - Month of start_time in YYYY-MM format + + **Measures:** + - `count` - Total number of observations + - `latency` - Observation latency (milliseconds) + - `streamingLatency` - Generation latency from completion start to end (milliseconds) + - `inputTokens` - Sum of input tokens consumed + - `outputTokens` - Sum of output tokens produced + - `totalTokens` - Sum of all tokens consumed + - `outputTokensPerSecond` - Output tokens per second + - `tokensPerSecond` - Total tokens per second + - `inputCost` - Input cost (USD) + - `outputCost` - Output cost (USD) + - `totalCost` - Total cost (USD) + - `timeToFirstToken` - Time to first token (milliseconds) + - `countScores` - Number of scores attached to the observation + + ### scores-numeric + Query numeric and boolean score data. + + **Dimensions:** + - `environment` - Deployment environment + - `name` - Name of the score (e.g., accuracy, toxicity) + - `source` - Origin of the score (API, ANNOTATION, EVAL) + - `dataType` - Data type (NUMERIC, BOOLEAN) + - `configId` - Identifier of the score config + - `timestampMonth` - Month in YYYY-MM format + - `timestampDay` - Day in YYYY-MM-DD format + - `value` - Numeric value of the score + - `traceName` - Name of the parent trace + - `tags` - Tags + - `traceRelease` - Release version + - `traceVersion` - Version + - `observationName` - Name of the associated observation + - `observationModelName` - Model name of the associated observation + - `observationPromptName` - Prompt name of the associated observation + - `observationPromptVersion` - Prompt version of the associated observation + + **Measures:** + - `count` - Total number of scores + - `value` - Score value (for aggregations) + + ### scores-categorical + Query categorical score data. Same dimensions as scores-numeric except uses `stringValue` instead of `value`. + + **Measures:** + - `count` - Total number of scores + + ## High Cardinality Dimensions + The following dimensions cannot be used as grouping dimensions in v2 metrics API as they can cause performance issues. + Use them in filters instead. + + **observations view:** + - `id` - Use traceId filter to narrow down results + - `traceId` - Use traceId filter instead + - `userId` - Use userId filter instead + - `sessionId` - Use sessionId filter instead + - `parentObservationId` - Use parentObservationId filter instead + + **scores-numeric / scores-categorical views:** + - `id` - Use specific filters to narrow down results + - `traceId` - Use traceId filter instead + - `userId` - Use userId filter instead + - `sessionId` - Use sessionId filter instead + - `observationId` - Use observationId filter instead + + ## Aggregations + Available aggregation functions: `sum`, `avg`, `count`, `max`, `min`, `p50`, `p75`, `p90`, `p95`, `p99`, `histogram` + + ## Time Granularities + Available granularities for timeDimension: `auto`, `minute`, `hour`, `day`, `week`, `month` + - `auto` bins the data into approximately 50 buckets based on the time range + + Parameters + ---------- + query : str + JSON string containing the query parameters with the following structure: + ```json + { + "view": string, // Required. One of "observations", "scores-numeric", "scores-categorical" + "dimensions": [ // Optional. Default: [] + { + "field": string // Field to group by (see available dimensions above) + } + ], + "metrics": [ // Required. At least one metric must be provided + { + "measure": string, // What to measure (see available measures above) + "aggregation": string // How to aggregate: "sum", "avg", "count", "max", "min", "p50", "p75", "p90", "p95", "p99", "histogram" + } + ], + "filters": [ // Optional. Default: [] + { + "column": string, // Column to filter on (any dimension field) + "operator": string, // Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject/numberObject: same as string/number with required "key" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Value to compare against + "type": string, // Data type: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "key": string // Required only for stringObject/numberObject types (e.g., metadata filtering) + } + ], + "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time + "granularity": string // One of "auto", "minute", "hour", "day", "week", "month" + }, + "fromTimestamp": string, // Required. ISO datetime string for start of time range + "toTimestamp": string, // Required. ISO datetime string for end of time range (must be after fromTimestamp) + "orderBy": [ // Optional. Default: null + { + "field": string, // Field to order by (dimension or metric alias) + "direction": string // "asc" or "desc" + } + ], + "config": { // Optional. Query-specific configuration + "bins": number, // Optional. Number of bins for histogram aggregation (1-100), default: 10 + "row_limit": number // Optional. Maximum number of rows to return (1-1000), default: 100 + } + } + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + MetricsV2Response + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.metrics_v2.metrics( + query="query", + ) + + + asyncio.run(main()) + """ + _response = await self._raw_client.metrics( + query=query, request_options=request_options + ) + return _response.data diff --git a/langfuse/api/metrics_v2/raw_client.py b/langfuse/api/metrics_v2/raw_client.py new file mode 100644 index 000000000..b79d55713 --- /dev/null +++ b/langfuse/api/metrics_v2/raw_client.py @@ -0,0 +1,530 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.metrics_v2response import MetricsV2Response + + +class RawMetricsV2Client: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def metrics( + self, *, query: str, request_options: typing.Optional[RequestOptions] = None + ) -> HttpResponse[MetricsV2Response]: + """ + Get metrics from the Langfuse project using a query object. V2 endpoint with optimized performance. + + ## V2 Differences + - Supports `observations`, `scores-numeric`, and `scores-categorical` views only (traces view not supported) + - Direct access to tags and release fields on observations + - Backwards-compatible: traceName, traceRelease, traceVersion dimensions are still available on observations view + - High cardinality dimensions are not supported and will return a 400 error (see below) + + For more details, see the [Metrics API documentation](https://langfuse.com/docs/metrics/features/metrics-api). + + ## Available Views + + ### observations + Query observation-level data (spans, generations, events). + + **Dimensions:** + - `environment` - Deployment environment (e.g., production, staging) + - `type` - Type of observation (SPAN, GENERATION, EVENT) + - `name` - Name of the observation + - `level` - Logging level of the observation + - `version` - Version of the observation + - `tags` - User-defined tags + - `release` - Release version + - `traceName` - Name of the parent trace (backwards-compatible) + - `traceRelease` - Release version of the parent trace (backwards-compatible, maps to release) + - `traceVersion` - Version of the parent trace (backwards-compatible, maps to version) + - `providedModelName` - Name of the model used + - `promptName` - Name of the prompt used + - `promptVersion` - Version of the prompt used + - `startTimeMonth` - Month of start_time in YYYY-MM format + + **Measures:** + - `count` - Total number of observations + - `latency` - Observation latency (milliseconds) + - `streamingLatency` - Generation latency from completion start to end (milliseconds) + - `inputTokens` - Sum of input tokens consumed + - `outputTokens` - Sum of output tokens produced + - `totalTokens` - Sum of all tokens consumed + - `outputTokensPerSecond` - Output tokens per second + - `tokensPerSecond` - Total tokens per second + - `inputCost` - Input cost (USD) + - `outputCost` - Output cost (USD) + - `totalCost` - Total cost (USD) + - `timeToFirstToken` - Time to first token (milliseconds) + - `countScores` - Number of scores attached to the observation + + ### scores-numeric + Query numeric and boolean score data. + + **Dimensions:** + - `environment` - Deployment environment + - `name` - Name of the score (e.g., accuracy, toxicity) + - `source` - Origin of the score (API, ANNOTATION, EVAL) + - `dataType` - Data type (NUMERIC, BOOLEAN) + - `configId` - Identifier of the score config + - `timestampMonth` - Month in YYYY-MM format + - `timestampDay` - Day in YYYY-MM-DD format + - `value` - Numeric value of the score + - `traceName` - Name of the parent trace + - `tags` - Tags + - `traceRelease` - Release version + - `traceVersion` - Version + - `observationName` - Name of the associated observation + - `observationModelName` - Model name of the associated observation + - `observationPromptName` - Prompt name of the associated observation + - `observationPromptVersion` - Prompt version of the associated observation + + **Measures:** + - `count` - Total number of scores + - `value` - Score value (for aggregations) + + ### scores-categorical + Query categorical score data. Same dimensions as scores-numeric except uses `stringValue` instead of `value`. + + **Measures:** + - `count` - Total number of scores + + ## High Cardinality Dimensions + The following dimensions cannot be used as grouping dimensions in v2 metrics API as they can cause performance issues. + Use them in filters instead. + + **observations view:** + - `id` - Use traceId filter to narrow down results + - `traceId` - Use traceId filter instead + - `userId` - Use userId filter instead + - `sessionId` - Use sessionId filter instead + - `parentObservationId` - Use parentObservationId filter instead + + **scores-numeric / scores-categorical views:** + - `id` - Use specific filters to narrow down results + - `traceId` - Use traceId filter instead + - `userId` - Use userId filter instead + - `sessionId` - Use sessionId filter instead + - `observationId` - Use observationId filter instead + + ## Aggregations + Available aggregation functions: `sum`, `avg`, `count`, `max`, `min`, `p50`, `p75`, `p90`, `p95`, `p99`, `histogram` + + ## Time Granularities + Available granularities for timeDimension: `auto`, `minute`, `hour`, `day`, `week`, `month` + - `auto` bins the data into approximately 50 buckets based on the time range + + Parameters + ---------- + query : str + JSON string containing the query parameters with the following structure: + ```json + { + "view": string, // Required. One of "observations", "scores-numeric", "scores-categorical" + "dimensions": [ // Optional. Default: [] + { + "field": string // Field to group by (see available dimensions above) + } + ], + "metrics": [ // Required. At least one metric must be provided + { + "measure": string, // What to measure (see available measures above) + "aggregation": string // How to aggregate: "sum", "avg", "count", "max", "min", "p50", "p75", "p90", "p95", "p99", "histogram" + } + ], + "filters": [ // Optional. Default: [] + { + "column": string, // Column to filter on (any dimension field) + "operator": string, // Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject/numberObject: same as string/number with required "key" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Value to compare against + "type": string, // Data type: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "key": string // Required only for stringObject/numberObject types (e.g., metadata filtering) + } + ], + "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time + "granularity": string // One of "auto", "minute", "hour", "day", "week", "month" + }, + "fromTimestamp": string, // Required. ISO datetime string for start of time range + "toTimestamp": string, // Required. ISO datetime string for end of time range (must be after fromTimestamp) + "orderBy": [ // Optional. Default: null + { + "field": string, // Field to order by (dimension or metric alias) + "direction": string // "asc" or "desc" + } + ], + "config": { // Optional. Query-specific configuration + "bins": number, // Optional. Number of bins for histogram aggregation (1-100), default: 10 + "row_limit": number // Optional. Maximum number of rows to return (1-1000), default: 100 + } + } + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[MetricsV2Response] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/v2/metrics", + method="GET", + params={ + "query": query, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MetricsV2Response, + parse_obj_as( + type_=MetricsV2Response, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawMetricsV2Client: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def metrics( + self, *, query: str, request_options: typing.Optional[RequestOptions] = None + ) -> AsyncHttpResponse[MetricsV2Response]: + """ + Get metrics from the Langfuse project using a query object. V2 endpoint with optimized performance. + + ## V2 Differences + - Supports `observations`, `scores-numeric`, and `scores-categorical` views only (traces view not supported) + - Direct access to tags and release fields on observations + - Backwards-compatible: traceName, traceRelease, traceVersion dimensions are still available on observations view + - High cardinality dimensions are not supported and will return a 400 error (see below) + + For more details, see the [Metrics API documentation](https://langfuse.com/docs/metrics/features/metrics-api). + + ## Available Views + + ### observations + Query observation-level data (spans, generations, events). + + **Dimensions:** + - `environment` - Deployment environment (e.g., production, staging) + - `type` - Type of observation (SPAN, GENERATION, EVENT) + - `name` - Name of the observation + - `level` - Logging level of the observation + - `version` - Version of the observation + - `tags` - User-defined tags + - `release` - Release version + - `traceName` - Name of the parent trace (backwards-compatible) + - `traceRelease` - Release version of the parent trace (backwards-compatible, maps to release) + - `traceVersion` - Version of the parent trace (backwards-compatible, maps to version) + - `providedModelName` - Name of the model used + - `promptName` - Name of the prompt used + - `promptVersion` - Version of the prompt used + - `startTimeMonth` - Month of start_time in YYYY-MM format + + **Measures:** + - `count` - Total number of observations + - `latency` - Observation latency (milliseconds) + - `streamingLatency` - Generation latency from completion start to end (milliseconds) + - `inputTokens` - Sum of input tokens consumed + - `outputTokens` - Sum of output tokens produced + - `totalTokens` - Sum of all tokens consumed + - `outputTokensPerSecond` - Output tokens per second + - `tokensPerSecond` - Total tokens per second + - `inputCost` - Input cost (USD) + - `outputCost` - Output cost (USD) + - `totalCost` - Total cost (USD) + - `timeToFirstToken` - Time to first token (milliseconds) + - `countScores` - Number of scores attached to the observation + + ### scores-numeric + Query numeric and boolean score data. + + **Dimensions:** + - `environment` - Deployment environment + - `name` - Name of the score (e.g., accuracy, toxicity) + - `source` - Origin of the score (API, ANNOTATION, EVAL) + - `dataType` - Data type (NUMERIC, BOOLEAN) + - `configId` - Identifier of the score config + - `timestampMonth` - Month in YYYY-MM format + - `timestampDay` - Day in YYYY-MM-DD format + - `value` - Numeric value of the score + - `traceName` - Name of the parent trace + - `tags` - Tags + - `traceRelease` - Release version + - `traceVersion` - Version + - `observationName` - Name of the associated observation + - `observationModelName` - Model name of the associated observation + - `observationPromptName` - Prompt name of the associated observation + - `observationPromptVersion` - Prompt version of the associated observation + + **Measures:** + - `count` - Total number of scores + - `value` - Score value (for aggregations) + + ### scores-categorical + Query categorical score data. Same dimensions as scores-numeric except uses `stringValue` instead of `value`. + + **Measures:** + - `count` - Total number of scores + + ## High Cardinality Dimensions + The following dimensions cannot be used as grouping dimensions in v2 metrics API as they can cause performance issues. + Use them in filters instead. + + **observations view:** + - `id` - Use traceId filter to narrow down results + - `traceId` - Use traceId filter instead + - `userId` - Use userId filter instead + - `sessionId` - Use sessionId filter instead + - `parentObservationId` - Use parentObservationId filter instead + + **scores-numeric / scores-categorical views:** + - `id` - Use specific filters to narrow down results + - `traceId` - Use traceId filter instead + - `userId` - Use userId filter instead + - `sessionId` - Use sessionId filter instead + - `observationId` - Use observationId filter instead + + ## Aggregations + Available aggregation functions: `sum`, `avg`, `count`, `max`, `min`, `p50`, `p75`, `p90`, `p95`, `p99`, `histogram` + + ## Time Granularities + Available granularities for timeDimension: `auto`, `minute`, `hour`, `day`, `week`, `month` + - `auto` bins the data into approximately 50 buckets based on the time range + + Parameters + ---------- + query : str + JSON string containing the query parameters with the following structure: + ```json + { + "view": string, // Required. One of "observations", "scores-numeric", "scores-categorical" + "dimensions": [ // Optional. Default: [] + { + "field": string // Field to group by (see available dimensions above) + } + ], + "metrics": [ // Required. At least one metric must be provided + { + "measure": string, // What to measure (see available measures above) + "aggregation": string // How to aggregate: "sum", "avg", "count", "max", "min", "p50", "p75", "p90", "p95", "p99", "histogram" + } + ], + "filters": [ // Optional. Default: [] + { + "column": string, // Column to filter on (any dimension field) + "operator": string, // Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject/numberObject: same as string/number with required "key" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Value to compare against + "type": string, // Data type: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "key": string // Required only for stringObject/numberObject types (e.g., metadata filtering) + } + ], + "timeDimension": { // Optional. Default: null. If provided, results will be grouped by time + "granularity": string // One of "auto", "minute", "hour", "day", "week", "month" + }, + "fromTimestamp": string, // Required. ISO datetime string for start of time range + "toTimestamp": string, // Required. ISO datetime string for end of time range (must be after fromTimestamp) + "orderBy": [ // Optional. Default: null + { + "field": string, // Field to order by (dimension or metric alias) + "direction": string // "asc" or "desc" + } + ], + "config": { // Optional. Query-specific configuration + "bins": number, // Optional. Number of bins for histogram aggregation (1-100), default: 10 + "row_limit": number // Optional. Maximum number of rows to return (1-1000), default: 100 + } + } + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[MetricsV2Response] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/v2/metrics", + method="GET", + params={ + "query": query, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + MetricsV2Response, + parse_obj_as( + type_=MetricsV2Response, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/metrics_v2/types/__init__.py b/langfuse/api/metrics_v2/types/__init__.py new file mode 100644 index 000000000..b9510d24f --- /dev/null +++ b/langfuse/api/metrics_v2/types/__init__.py @@ -0,0 +1,40 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .metrics_v2response import MetricsV2Response +_dynamic_imports: typing.Dict[str, str] = {"MetricsV2Response": ".metrics_v2response"} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["MetricsV2Response"] diff --git a/langfuse/api/metrics_v2/types/metrics_v2response.py b/langfuse/api/metrics_v2/types/metrics_v2response.py new file mode 100644 index 000000000..64d26f392 --- /dev/null +++ b/langfuse/api/metrics_v2/types/metrics_v2response.py @@ -0,0 +1,26 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class MetricsV2Response(UniversalBaseModel): + data: typing.List[typing.Dict[str, typing.Any]] = pydantic.Field() + """ + The metrics data. Each item in the list contains the metric values and dimensions requested in the query. + Format varies based on the query parameters. + Histograms will return an array with [lower, upper, height] tuples. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/observations_v2/__init__.py b/langfuse/api/observations_v2/__init__.py new file mode 100644 index 000000000..66816e540 --- /dev/null +++ b/langfuse/api/observations_v2/__init__.py @@ -0,0 +1,43 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .types import ObservationsV2Meta, ObservationsV2Response +_dynamic_imports: typing.Dict[str, str] = { + "ObservationsV2Meta": ".types", + "ObservationsV2Response": ".types", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["ObservationsV2Meta", "ObservationsV2Response"] diff --git a/langfuse/api/observations_v2/client.py b/langfuse/api/observations_v2/client.py new file mode 100644 index 000000000..5594c3dc5 --- /dev/null +++ b/langfuse/api/observations_v2/client.py @@ -0,0 +1,504 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing + +from ..commons.types.observation_level import ObservationLevel +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.request_options import RequestOptions +from .raw_client import AsyncRawObservationsV2Client, RawObservationsV2Client +from .types.observations_v2response import ObservationsV2Response + + +class ObservationsV2Client: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._raw_client = RawObservationsV2Client(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> RawObservationsV2Client: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + RawObservationsV2Client + """ + return self._raw_client + + def get_many( + self, + *, + fields: typing.Optional[str] = None, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + parse_io_as_json: typing.Optional[bool] = None, + name: typing.Optional[str] = None, + user_id: typing.Optional[str] = None, + type: typing.Optional[str] = None, + trace_id: typing.Optional[str] = None, + level: typing.Optional[ObservationLevel] = None, + parent_observation_id: typing.Optional[str] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + from_start_time: typing.Optional[dt.datetime] = None, + to_start_time: typing.Optional[dt.datetime] = None, + version: typing.Optional[str] = None, + filter: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ObservationsV2Response: + """ + Get a list of observations with cursor-based pagination and flexible field selection. + + ## Cursor-based Pagination + This endpoint uses cursor-based pagination for efficient traversal of large datasets. + The cursor is returned in the response metadata and should be passed in subsequent requests + to retrieve the next page of results. + + ## Field Selection + Use the `fields` parameter to control which observation fields are returned: + - `core` - Always included: id, traceId, startTime, endTime, projectId, parentObservationId, type + - `basic` - name, level, statusMessage, version, environment, bookmarked, public, userId, sessionId + - `time` - completionStartTime, createdAt, updatedAt + - `io` - input, output + - `metadata` - metadata + - `model` - providedModelName, internalModelId, modelParameters + - `usage` - usageDetails, costDetails, totalCost + - `prompt` - promptId, promptName, promptVersion + - `metrics` - latency, timeToFirstToken + + If not specified, `core` and `basic` field groups are returned. + + ## Filters + Multiple filtering options are available via query parameters or the structured `filter` parameter. + When using the `filter` parameter, it takes precedence over individual query parameter filters. + + Parameters + ---------- + fields : typing.Optional[str] + Comma-separated list of field groups to include in the response. + Available groups: core, basic, time, io, metadata, model, usage, prompt, metrics. + If not specified, `core` and `basic` field groups are returned. + Example: "basic,usage,model" + + limit : typing.Optional[int] + Number of items to return per page. Maximum 1000, default 50. + + cursor : typing.Optional[str] + Base64-encoded cursor for pagination. Use the cursor from the previous response to get the next page. + + parse_io_as_json : typing.Optional[bool] + Set to `true` to parse input/output fields as JSON, or `false` to return raw strings. + Defaults to `false` if not provided. + + name : typing.Optional[str] + + user_id : typing.Optional[str] + + type : typing.Optional[str] + Filter by observation type (e.g., "GENERATION", "SPAN", "EVENT", "AGENT", "TOOL", "CHAIN", "RETRIEVER", "EVALUATOR", "EMBEDDING", "GUARDRAIL") + + trace_id : typing.Optional[str] + + level : typing.Optional[ObservationLevel] + Optional filter for observations with a specific level (e.g. "DEBUG", "DEFAULT", "WARNING", "ERROR"). + + parent_observation_id : typing.Optional[str] + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for observations where the environment is one of the provided values. + + from_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time on or after this datetime (ISO 8601). + + to_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time before this datetime (ISO 8601). + + version : typing.Optional[str] + Optional filter to only include observations with a certain version. + + filter : typing.Optional[str] + JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, type, level, environment, fromStartTime, ...). + + ## Filter Structure + Each filter condition has the following structure: + ```json + [ + { + "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "column": string, // Required. Column to filter on (see available columns below) + "operator": string, // Required. Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - categoryOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject: "=", "contains", "does not contain", "starts with", "ends with" + // - numberObject: "=", ">", "<", ">=", "<=" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Required (except for null type). Value to compare against. Type depends on filter type + "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata + } + ] + ``` + + ## Available Columns + + ### Core Observation Fields + - `id` (string) - Observation ID + - `type` (string) - Observation type (SPAN, GENERATION, EVENT) + - `name` (string) - Observation name + - `traceId` (string) - Associated trace ID + - `startTime` (datetime) - Observation start time + - `endTime` (datetime) - Observation end time + - `environment` (string) - Environment tag + - `level` (string) - Log level (DEBUG, DEFAULT, WARNING, ERROR) + - `statusMessage` (string) - Status message + - `version` (string) - Version tag + - `userId` (string) - User ID + - `sessionId` (string) - Session ID + + ### Trace-Related Fields + - `traceName` (string) - Name of the parent trace + - `traceTags` (arrayOptions) - Tags from the parent trace + - `tags` (arrayOptions) - Alias for traceTags + + ### Performance Metrics + - `latency` (number) - Latency in seconds (calculated: end_time - start_time) + - `timeToFirstToken` (number) - Time to first token in seconds + - `tokensPerSecond` (number) - Output tokens per second + + ### Token Usage + - `inputTokens` (number) - Number of input tokens + - `outputTokens` (number) - Number of output tokens + - `totalTokens` (number) - Total tokens (alias: `tokens`) + + ### Cost Metrics + - `inputCost` (number) - Input cost in USD + - `outputCost` (number) - Output cost in USD + - `totalCost` (number) - Total cost in USD + + ### Model Information + - `model` (string) - Provided model name (alias: `providedModelName`) + - `promptName` (string) - Associated prompt name + - `promptVersion` (number) - Associated prompt version + + ### Structured Data + - `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys. + + ## Filter Examples + ```json + [ + { + "type": "string", + "column": "type", + "operator": "=", + "value": "GENERATION" + }, + { + "type": "number", + "column": "latency", + "operator": ">=", + "value": 2.5 + }, + { + "type": "stringObject", + "column": "metadata", + "key": "environment", + "operator": "=", + "value": "production" + } + ] + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ObservationsV2Response + + Examples + -------- + from langfuse import LangfuseAPI + + client = LangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + client.observations_v2.get_many() + """ + _response = self._raw_client.get_many( + fields=fields, + limit=limit, + cursor=cursor, + parse_io_as_json=parse_io_as_json, + name=name, + user_id=user_id, + type=type, + trace_id=trace_id, + level=level, + parent_observation_id=parent_observation_id, + environment=environment, + from_start_time=from_start_time, + to_start_time=to_start_time, + version=version, + filter=filter, + request_options=request_options, + ) + return _response.data + + +class AsyncObservationsV2Client: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._raw_client = AsyncRawObservationsV2Client(client_wrapper=client_wrapper) + + @property + def with_raw_response(self) -> AsyncRawObservationsV2Client: + """ + Retrieves a raw implementation of this client that returns raw responses. + + Returns + ------- + AsyncRawObservationsV2Client + """ + return self._raw_client + + async def get_many( + self, + *, + fields: typing.Optional[str] = None, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + parse_io_as_json: typing.Optional[bool] = None, + name: typing.Optional[str] = None, + user_id: typing.Optional[str] = None, + type: typing.Optional[str] = None, + trace_id: typing.Optional[str] = None, + level: typing.Optional[ObservationLevel] = None, + parent_observation_id: typing.Optional[str] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + from_start_time: typing.Optional[dt.datetime] = None, + to_start_time: typing.Optional[dt.datetime] = None, + version: typing.Optional[str] = None, + filter: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> ObservationsV2Response: + """ + Get a list of observations with cursor-based pagination and flexible field selection. + + ## Cursor-based Pagination + This endpoint uses cursor-based pagination for efficient traversal of large datasets. + The cursor is returned in the response metadata and should be passed in subsequent requests + to retrieve the next page of results. + + ## Field Selection + Use the `fields` parameter to control which observation fields are returned: + - `core` - Always included: id, traceId, startTime, endTime, projectId, parentObservationId, type + - `basic` - name, level, statusMessage, version, environment, bookmarked, public, userId, sessionId + - `time` - completionStartTime, createdAt, updatedAt + - `io` - input, output + - `metadata` - metadata + - `model` - providedModelName, internalModelId, modelParameters + - `usage` - usageDetails, costDetails, totalCost + - `prompt` - promptId, promptName, promptVersion + - `metrics` - latency, timeToFirstToken + + If not specified, `core` and `basic` field groups are returned. + + ## Filters + Multiple filtering options are available via query parameters or the structured `filter` parameter. + When using the `filter` parameter, it takes precedence over individual query parameter filters. + + Parameters + ---------- + fields : typing.Optional[str] + Comma-separated list of field groups to include in the response. + Available groups: core, basic, time, io, metadata, model, usage, prompt, metrics. + If not specified, `core` and `basic` field groups are returned. + Example: "basic,usage,model" + + limit : typing.Optional[int] + Number of items to return per page. Maximum 1000, default 50. + + cursor : typing.Optional[str] + Base64-encoded cursor for pagination. Use the cursor from the previous response to get the next page. + + parse_io_as_json : typing.Optional[bool] + Set to `true` to parse input/output fields as JSON, or `false` to return raw strings. + Defaults to `false` if not provided. + + name : typing.Optional[str] + + user_id : typing.Optional[str] + + type : typing.Optional[str] + Filter by observation type (e.g., "GENERATION", "SPAN", "EVENT", "AGENT", "TOOL", "CHAIN", "RETRIEVER", "EVALUATOR", "EMBEDDING", "GUARDRAIL") + + trace_id : typing.Optional[str] + + level : typing.Optional[ObservationLevel] + Optional filter for observations with a specific level (e.g. "DEBUG", "DEFAULT", "WARNING", "ERROR"). + + parent_observation_id : typing.Optional[str] + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for observations where the environment is one of the provided values. + + from_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time on or after this datetime (ISO 8601). + + to_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time before this datetime (ISO 8601). + + version : typing.Optional[str] + Optional filter to only include observations with a certain version. + + filter : typing.Optional[str] + JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, type, level, environment, fromStartTime, ...). + + ## Filter Structure + Each filter condition has the following structure: + ```json + [ + { + "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "column": string, // Required. Column to filter on (see available columns below) + "operator": string, // Required. Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - categoryOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject: "=", "contains", "does not contain", "starts with", "ends with" + // - numberObject: "=", ">", "<", ">=", "<=" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Required (except for null type). Value to compare against. Type depends on filter type + "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata + } + ] + ``` + + ## Available Columns + + ### Core Observation Fields + - `id` (string) - Observation ID + - `type` (string) - Observation type (SPAN, GENERATION, EVENT) + - `name` (string) - Observation name + - `traceId` (string) - Associated trace ID + - `startTime` (datetime) - Observation start time + - `endTime` (datetime) - Observation end time + - `environment` (string) - Environment tag + - `level` (string) - Log level (DEBUG, DEFAULT, WARNING, ERROR) + - `statusMessage` (string) - Status message + - `version` (string) - Version tag + - `userId` (string) - User ID + - `sessionId` (string) - Session ID + + ### Trace-Related Fields + - `traceName` (string) - Name of the parent trace + - `traceTags` (arrayOptions) - Tags from the parent trace + - `tags` (arrayOptions) - Alias for traceTags + + ### Performance Metrics + - `latency` (number) - Latency in seconds (calculated: end_time - start_time) + - `timeToFirstToken` (number) - Time to first token in seconds + - `tokensPerSecond` (number) - Output tokens per second + + ### Token Usage + - `inputTokens` (number) - Number of input tokens + - `outputTokens` (number) - Number of output tokens + - `totalTokens` (number) - Total tokens (alias: `tokens`) + + ### Cost Metrics + - `inputCost` (number) - Input cost in USD + - `outputCost` (number) - Output cost in USD + - `totalCost` (number) - Total cost in USD + + ### Model Information + - `model` (string) - Provided model name (alias: `providedModelName`) + - `promptName` (string) - Associated prompt name + - `promptVersion` (number) - Associated prompt version + + ### Structured Data + - `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys. + + ## Filter Examples + ```json + [ + { + "type": "string", + "column": "type", + "operator": "=", + "value": "GENERATION" + }, + { + "type": "number", + "column": "latency", + "operator": ">=", + "value": 2.5 + }, + { + "type": "stringObject", + "column": "metadata", + "key": "environment", + "operator": "=", + "value": "production" + } + ] + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + ObservationsV2Response + + Examples + -------- + import asyncio + + from langfuse import AsyncLangfuseAPI + + client = AsyncLangfuseAPI( + x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", + x_langfuse_sdk_version="YOUR_X_LANGFUSE_SDK_VERSION", + x_langfuse_public_key="YOUR_X_LANGFUSE_PUBLIC_KEY", + username="YOUR_USERNAME", + password="YOUR_PASSWORD", + base_url="https://yourhost.com/path/to/api", + ) + + + async def main() -> None: + await client.observations_v2.get_many() + + + asyncio.run(main()) + """ + _response = await self._raw_client.get_many( + fields=fields, + limit=limit, + cursor=cursor, + parse_io_as_json=parse_io_as_json, + name=name, + user_id=user_id, + type=type, + trace_id=trace_id, + level=level, + parent_observation_id=parent_observation_id, + environment=environment, + from_start_time=from_start_time, + to_start_time=to_start_time, + version=version, + filter=filter, + request_options=request_options, + ) + return _response.data diff --git a/langfuse/api/observations_v2/raw_client.py b/langfuse/api/observations_v2/raw_client.py new file mode 100644 index 000000000..d80bc948f --- /dev/null +++ b/langfuse/api/observations_v2/raw_client.py @@ -0,0 +1,623 @@ +# This file was auto-generated by Fern from our API Definition. + +import datetime as dt +import typing +from json.decoder import JSONDecodeError + +from ..commons.errors.access_denied_error import AccessDeniedError +from ..commons.errors.error import Error +from ..commons.errors.method_not_allowed_error import MethodNotAllowedError +from ..commons.errors.not_found_error import NotFoundError +from ..commons.errors.unauthorized_error import UnauthorizedError +from ..commons.types.observation_level import ObservationLevel +from ..core.api_error import ApiError +from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper +from ..core.datetime_utils import serialize_datetime +from ..core.http_response import AsyncHttpResponse, HttpResponse +from ..core.pydantic_utilities import parse_obj_as +from ..core.request_options import RequestOptions +from .types.observations_v2response import ObservationsV2Response + + +class RawObservationsV2Client: + def __init__(self, *, client_wrapper: SyncClientWrapper): + self._client_wrapper = client_wrapper + + def get_many( + self, + *, + fields: typing.Optional[str] = None, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + parse_io_as_json: typing.Optional[bool] = None, + name: typing.Optional[str] = None, + user_id: typing.Optional[str] = None, + type: typing.Optional[str] = None, + trace_id: typing.Optional[str] = None, + level: typing.Optional[ObservationLevel] = None, + parent_observation_id: typing.Optional[str] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + from_start_time: typing.Optional[dt.datetime] = None, + to_start_time: typing.Optional[dt.datetime] = None, + version: typing.Optional[str] = None, + filter: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> HttpResponse[ObservationsV2Response]: + """ + Get a list of observations with cursor-based pagination and flexible field selection. + + ## Cursor-based Pagination + This endpoint uses cursor-based pagination for efficient traversal of large datasets. + The cursor is returned in the response metadata and should be passed in subsequent requests + to retrieve the next page of results. + + ## Field Selection + Use the `fields` parameter to control which observation fields are returned: + - `core` - Always included: id, traceId, startTime, endTime, projectId, parentObservationId, type + - `basic` - name, level, statusMessage, version, environment, bookmarked, public, userId, sessionId + - `time` - completionStartTime, createdAt, updatedAt + - `io` - input, output + - `metadata` - metadata + - `model` - providedModelName, internalModelId, modelParameters + - `usage` - usageDetails, costDetails, totalCost + - `prompt` - promptId, promptName, promptVersion + - `metrics` - latency, timeToFirstToken + + If not specified, `core` and `basic` field groups are returned. + + ## Filters + Multiple filtering options are available via query parameters or the structured `filter` parameter. + When using the `filter` parameter, it takes precedence over individual query parameter filters. + + Parameters + ---------- + fields : typing.Optional[str] + Comma-separated list of field groups to include in the response. + Available groups: core, basic, time, io, metadata, model, usage, prompt, metrics. + If not specified, `core` and `basic` field groups are returned. + Example: "basic,usage,model" + + limit : typing.Optional[int] + Number of items to return per page. Maximum 1000, default 50. + + cursor : typing.Optional[str] + Base64-encoded cursor for pagination. Use the cursor from the previous response to get the next page. + + parse_io_as_json : typing.Optional[bool] + Set to `true` to parse input/output fields as JSON, or `false` to return raw strings. + Defaults to `false` if not provided. + + name : typing.Optional[str] + + user_id : typing.Optional[str] + + type : typing.Optional[str] + Filter by observation type (e.g., "GENERATION", "SPAN", "EVENT", "AGENT", "TOOL", "CHAIN", "RETRIEVER", "EVALUATOR", "EMBEDDING", "GUARDRAIL") + + trace_id : typing.Optional[str] + + level : typing.Optional[ObservationLevel] + Optional filter for observations with a specific level (e.g. "DEBUG", "DEFAULT", "WARNING", "ERROR"). + + parent_observation_id : typing.Optional[str] + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for observations where the environment is one of the provided values. + + from_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time on or after this datetime (ISO 8601). + + to_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time before this datetime (ISO 8601). + + version : typing.Optional[str] + Optional filter to only include observations with a certain version. + + filter : typing.Optional[str] + JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, type, level, environment, fromStartTime, ...). + + ## Filter Structure + Each filter condition has the following structure: + ```json + [ + { + "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "column": string, // Required. Column to filter on (see available columns below) + "operator": string, // Required. Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - categoryOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject: "=", "contains", "does not contain", "starts with", "ends with" + // - numberObject: "=", ">", "<", ">=", "<=" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Required (except for null type). Value to compare against. Type depends on filter type + "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata + } + ] + ``` + + ## Available Columns + + ### Core Observation Fields + - `id` (string) - Observation ID + - `type` (string) - Observation type (SPAN, GENERATION, EVENT) + - `name` (string) - Observation name + - `traceId` (string) - Associated trace ID + - `startTime` (datetime) - Observation start time + - `endTime` (datetime) - Observation end time + - `environment` (string) - Environment tag + - `level` (string) - Log level (DEBUG, DEFAULT, WARNING, ERROR) + - `statusMessage` (string) - Status message + - `version` (string) - Version tag + - `userId` (string) - User ID + - `sessionId` (string) - Session ID + + ### Trace-Related Fields + - `traceName` (string) - Name of the parent trace + - `traceTags` (arrayOptions) - Tags from the parent trace + - `tags` (arrayOptions) - Alias for traceTags + + ### Performance Metrics + - `latency` (number) - Latency in seconds (calculated: end_time - start_time) + - `timeToFirstToken` (number) - Time to first token in seconds + - `tokensPerSecond` (number) - Output tokens per second + + ### Token Usage + - `inputTokens` (number) - Number of input tokens + - `outputTokens` (number) - Number of output tokens + - `totalTokens` (number) - Total tokens (alias: `tokens`) + + ### Cost Metrics + - `inputCost` (number) - Input cost in USD + - `outputCost` (number) - Output cost in USD + - `totalCost` (number) - Total cost in USD + + ### Model Information + - `model` (string) - Provided model name (alias: `providedModelName`) + - `promptName` (string) - Associated prompt name + - `promptVersion` (number) - Associated prompt version + + ### Structured Data + - `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys. + + ## Filter Examples + ```json + [ + { + "type": "string", + "column": "type", + "operator": "=", + "value": "GENERATION" + }, + { + "type": "number", + "column": "latency", + "operator": ">=", + "value": 2.5 + }, + { + "type": "stringObject", + "column": "metadata", + "key": "environment", + "operator": "=", + "value": "production" + } + ] + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + HttpResponse[ObservationsV2Response] + """ + _response = self._client_wrapper.httpx_client.request( + "api/public/v2/observations", + method="GET", + params={ + "fields": fields, + "limit": limit, + "cursor": cursor, + "parseIoAsJson": parse_io_as_json, + "name": name, + "userId": user_id, + "type": type, + "traceId": trace_id, + "level": level, + "parentObservationId": parent_observation_id, + "environment": environment, + "fromStartTime": serialize_datetime(from_start_time) + if from_start_time is not None + else None, + "toStartTime": serialize_datetime(to_start_time) + if to_start_time is not None + else None, + "version": version, + "filter": filter, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ObservationsV2Response, + parse_obj_as( + type_=ObservationsV2Response, # type: ignore + object_=_response.json(), + ), + ) + return HttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) + + +class AsyncRawObservationsV2Client: + def __init__(self, *, client_wrapper: AsyncClientWrapper): + self._client_wrapper = client_wrapper + + async def get_many( + self, + *, + fields: typing.Optional[str] = None, + limit: typing.Optional[int] = None, + cursor: typing.Optional[str] = None, + parse_io_as_json: typing.Optional[bool] = None, + name: typing.Optional[str] = None, + user_id: typing.Optional[str] = None, + type: typing.Optional[str] = None, + trace_id: typing.Optional[str] = None, + level: typing.Optional[ObservationLevel] = None, + parent_observation_id: typing.Optional[str] = None, + environment: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None, + from_start_time: typing.Optional[dt.datetime] = None, + to_start_time: typing.Optional[dt.datetime] = None, + version: typing.Optional[str] = None, + filter: typing.Optional[str] = None, + request_options: typing.Optional[RequestOptions] = None, + ) -> AsyncHttpResponse[ObservationsV2Response]: + """ + Get a list of observations with cursor-based pagination and flexible field selection. + + ## Cursor-based Pagination + This endpoint uses cursor-based pagination for efficient traversal of large datasets. + The cursor is returned in the response metadata and should be passed in subsequent requests + to retrieve the next page of results. + + ## Field Selection + Use the `fields` parameter to control which observation fields are returned: + - `core` - Always included: id, traceId, startTime, endTime, projectId, parentObservationId, type + - `basic` - name, level, statusMessage, version, environment, bookmarked, public, userId, sessionId + - `time` - completionStartTime, createdAt, updatedAt + - `io` - input, output + - `metadata` - metadata + - `model` - providedModelName, internalModelId, modelParameters + - `usage` - usageDetails, costDetails, totalCost + - `prompt` - promptId, promptName, promptVersion + - `metrics` - latency, timeToFirstToken + + If not specified, `core` and `basic` field groups are returned. + + ## Filters + Multiple filtering options are available via query parameters or the structured `filter` parameter. + When using the `filter` parameter, it takes precedence over individual query parameter filters. + + Parameters + ---------- + fields : typing.Optional[str] + Comma-separated list of field groups to include in the response. + Available groups: core, basic, time, io, metadata, model, usage, prompt, metrics. + If not specified, `core` and `basic` field groups are returned. + Example: "basic,usage,model" + + limit : typing.Optional[int] + Number of items to return per page. Maximum 1000, default 50. + + cursor : typing.Optional[str] + Base64-encoded cursor for pagination. Use the cursor from the previous response to get the next page. + + parse_io_as_json : typing.Optional[bool] + Set to `true` to parse input/output fields as JSON, or `false` to return raw strings. + Defaults to `false` if not provided. + + name : typing.Optional[str] + + user_id : typing.Optional[str] + + type : typing.Optional[str] + Filter by observation type (e.g., "GENERATION", "SPAN", "EVENT", "AGENT", "TOOL", "CHAIN", "RETRIEVER", "EVALUATOR", "EMBEDDING", "GUARDRAIL") + + trace_id : typing.Optional[str] + + level : typing.Optional[ObservationLevel] + Optional filter for observations with a specific level (e.g. "DEBUG", "DEFAULT", "WARNING", "ERROR"). + + parent_observation_id : typing.Optional[str] + + environment : typing.Optional[typing.Union[str, typing.Sequence[str]]] + Optional filter for observations where the environment is one of the provided values. + + from_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time on or after this datetime (ISO 8601). + + to_start_time : typing.Optional[dt.datetime] + Retrieve only observations with a start_time before this datetime (ISO 8601). + + version : typing.Optional[str] + Optional filter to only include observations with a certain version. + + filter : typing.Optional[str] + JSON string containing an array of filter conditions. When provided, this takes precedence over query parameter filters (userId, name, type, level, environment, fromStartTime, ...). + + ## Filter Structure + Each filter condition has the following structure: + ```json + [ + { + "type": string, // Required. One of: "datetime", "string", "number", "stringOptions", "categoryOptions", "arrayOptions", "stringObject", "numberObject", "boolean", "null" + "column": string, // Required. Column to filter on (see available columns below) + "operator": string, // Required. Operator based on type: + // - datetime: ">", "<", ">=", "<=" + // - string: "=", "contains", "does not contain", "starts with", "ends with" + // - stringOptions: "any of", "none of" + // - categoryOptions: "any of", "none of" + // - arrayOptions: "any of", "none of", "all of" + // - number: "=", ">", "<", ">=", "<=" + // - stringObject: "=", "contains", "does not contain", "starts with", "ends with" + // - numberObject: "=", ">", "<", ">=", "<=" + // - boolean: "=", "<>" + // - null: "is null", "is not null" + "value": any, // Required (except for null type). Value to compare against. Type depends on filter type + "key": string // Required only for stringObject, numberObject, and categoryOptions types when filtering on nested fields like metadata + } + ] + ``` + + ## Available Columns + + ### Core Observation Fields + - `id` (string) - Observation ID + - `type` (string) - Observation type (SPAN, GENERATION, EVENT) + - `name` (string) - Observation name + - `traceId` (string) - Associated trace ID + - `startTime` (datetime) - Observation start time + - `endTime` (datetime) - Observation end time + - `environment` (string) - Environment tag + - `level` (string) - Log level (DEBUG, DEFAULT, WARNING, ERROR) + - `statusMessage` (string) - Status message + - `version` (string) - Version tag + - `userId` (string) - User ID + - `sessionId` (string) - Session ID + + ### Trace-Related Fields + - `traceName` (string) - Name of the parent trace + - `traceTags` (arrayOptions) - Tags from the parent trace + - `tags` (arrayOptions) - Alias for traceTags + + ### Performance Metrics + - `latency` (number) - Latency in seconds (calculated: end_time - start_time) + - `timeToFirstToken` (number) - Time to first token in seconds + - `tokensPerSecond` (number) - Output tokens per second + + ### Token Usage + - `inputTokens` (number) - Number of input tokens + - `outputTokens` (number) - Number of output tokens + - `totalTokens` (number) - Total tokens (alias: `tokens`) + + ### Cost Metrics + - `inputCost` (number) - Input cost in USD + - `outputCost` (number) - Output cost in USD + - `totalCost` (number) - Total cost in USD + + ### Model Information + - `model` (string) - Provided model name (alias: `providedModelName`) + - `promptName` (string) - Associated prompt name + - `promptVersion` (number) - Associated prompt version + + ### Structured Data + - `metadata` (stringObject/numberObject/categoryOptions) - Metadata key-value pairs. Use `key` parameter to filter on specific metadata keys. + + ## Filter Examples + ```json + [ + { + "type": "string", + "column": "type", + "operator": "=", + "value": "GENERATION" + }, + { + "type": "number", + "column": "latency", + "operator": ">=", + "value": 2.5 + }, + { + "type": "stringObject", + "column": "metadata", + "key": "environment", + "operator": "=", + "value": "production" + } + ] + ``` + + request_options : typing.Optional[RequestOptions] + Request-specific configuration. + + Returns + ------- + AsyncHttpResponse[ObservationsV2Response] + """ + _response = await self._client_wrapper.httpx_client.request( + "api/public/v2/observations", + method="GET", + params={ + "fields": fields, + "limit": limit, + "cursor": cursor, + "parseIoAsJson": parse_io_as_json, + "name": name, + "userId": user_id, + "type": type, + "traceId": trace_id, + "level": level, + "parentObservationId": parent_observation_id, + "environment": environment, + "fromStartTime": serialize_datetime(from_start_time) + if from_start_time is not None + else None, + "toStartTime": serialize_datetime(to_start_time) + if to_start_time is not None + else None, + "version": version, + "filter": filter, + }, + request_options=request_options, + ) + try: + if 200 <= _response.status_code < 300: + _data = typing.cast( + ObservationsV2Response, + parse_obj_as( + type_=ObservationsV2Response, # type: ignore + object_=_response.json(), + ), + ) + return AsyncHttpResponse(response=_response, data=_data) + if _response.status_code == 400: + raise Error( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 401: + raise UnauthorizedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 403: + raise AccessDeniedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 405: + raise MethodNotAllowedError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + if _response.status_code == 404: + raise NotFoundError( + headers=dict(_response.headers), + body=typing.cast( + typing.Any, + parse_obj_as( + type_=typing.Any, # type: ignore + object_=_response.json(), + ), + ), + ) + _response_json = _response.json() + except JSONDecodeError: + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response.text, + ) + raise ApiError( + status_code=_response.status_code, + headers=dict(_response.headers), + body=_response_json, + ) diff --git a/langfuse/api/observations_v2/types/__init__.py b/langfuse/api/observations_v2/types/__init__.py new file mode 100644 index 000000000..6e132aba6 --- /dev/null +++ b/langfuse/api/observations_v2/types/__init__.py @@ -0,0 +1,44 @@ +# This file was auto-generated by Fern from our API Definition. + +# isort: skip_file + +import typing +from importlib import import_module + +if typing.TYPE_CHECKING: + from .observations_v2meta import ObservationsV2Meta + from .observations_v2response import ObservationsV2Response +_dynamic_imports: typing.Dict[str, str] = { + "ObservationsV2Meta": ".observations_v2meta", + "ObservationsV2Response": ".observations_v2response", +} + + +def __getattr__(attr_name: str) -> typing.Any: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__}" + ) + try: + module = import_module(module_name, __package__) + if module_name == f".{attr_name}": + return module + else: + return getattr(module, attr_name) + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) + + +__all__ = ["ObservationsV2Meta", "ObservationsV2Response"] diff --git a/langfuse/api/observations_v2/types/observations_v2meta.py b/langfuse/api/observations_v2/types/observations_v2meta.py new file mode 100644 index 000000000..6d03b2e4d --- /dev/null +++ b/langfuse/api/observations_v2/types/observations_v2meta.py @@ -0,0 +1,28 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel + + +class ObservationsV2Meta(UniversalBaseModel): + """ + Metadata for cursor-based pagination + """ + + cursor: typing.Optional[str] = pydantic.Field(default=None) + """ + Base64-encoded cursor to use for retrieving the next page. If not present, there are no more results. + """ + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/observations_v2/types/observations_v2response.py b/langfuse/api/observations_v2/types/observations_v2response.py new file mode 100644 index 000000000..ab0b43bd6 --- /dev/null +++ b/langfuse/api/observations_v2/types/observations_v2response.py @@ -0,0 +1,34 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +import pydantic +from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from .observations_v2meta import ObservationsV2Meta + + +class ObservationsV2Response(UniversalBaseModel): + """ + Response containing observations with field-group-based filtering and cursor-based pagination. + + The `data` array contains observation objects with only the requested field groups included. + Use the `cursor` in `meta` to retrieve the next page of results. + """ + + data: typing.List[typing.Dict[str, typing.Any]] = pydantic.Field() + """ + Array of observation objects. Fields included depend on the `fields` parameter in the request. + """ + + meta: ObservationsV2Meta + + if IS_PYDANTIC_V2: + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) # type: ignore # Pydantic v2 + else: + + class Config: + frozen = True + smart_union = True + extra = pydantic.Extra.allow diff --git a/langfuse/api/prompts/__init__.py b/langfuse/api/prompts/__init__.py index e310c0193..27e0a999d 100644 --- a/langfuse/api/prompts/__init__.py +++ b/langfuse/api/prompts/__init__.py @@ -10,14 +10,12 @@ BasePrompt, ChatMessage, ChatMessageWithPlaceholders, - ChatMessageWithPlaceholders_Chatmessage, - ChatMessageWithPlaceholders_Placeholder, ChatPrompt, CreateChatPromptRequest, + CreateChatPromptType, CreatePromptRequest, - CreatePromptRequest_Chat, - CreatePromptRequest_Text, CreateTextPromptRequest, + CreateTextPromptType, PlaceholderMessage, Prompt, PromptMeta, @@ -31,14 +29,12 @@ "BasePrompt": ".types", "ChatMessage": ".types", "ChatMessageWithPlaceholders": ".types", - "ChatMessageWithPlaceholders_Chatmessage": ".types", - "ChatMessageWithPlaceholders_Placeholder": ".types", "ChatPrompt": ".types", "CreateChatPromptRequest": ".types", + "CreateChatPromptType": ".types", "CreatePromptRequest": ".types", - "CreatePromptRequest_Chat": ".types", - "CreatePromptRequest_Text": ".types", "CreateTextPromptRequest": ".types", + "CreateTextPromptType": ".types", "PlaceholderMessage": ".types", "Prompt": ".types", "PromptMeta": ".types", @@ -81,14 +77,12 @@ def __dir__(): "BasePrompt", "ChatMessage", "ChatMessageWithPlaceholders", - "ChatMessageWithPlaceholders_Chatmessage", - "ChatMessageWithPlaceholders_Placeholder", "ChatPrompt", "CreateChatPromptRequest", + "CreateChatPromptType", "CreatePromptRequest", - "CreatePromptRequest_Chat", - "CreatePromptRequest_Text", "CreateTextPromptRequest", + "CreateTextPromptType", "PlaceholderMessage", "Prompt", "PromptMeta", diff --git a/langfuse/api/prompts/client.py b/langfuse/api/prompts/client.py index 09f9b43ad..cb1fd9917 100644 --- a/langfuse/api/prompts/client.py +++ b/langfuse/api/prompts/client.py @@ -171,10 +171,7 @@ def create( Examples -------- from langfuse import LangfuseAPI - from langfuse.prompts import ( - ChatMessageWithPlaceholders_Chatmessage, - CreatePromptRequest_Chat, - ) + from langfuse.prompts import ChatMessage, CreateChatPromptRequest client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -185,18 +182,19 @@ def create( base_url="https://yourhost.com/path/to/api", ) client.prompts.create( - request=CreatePromptRequest_Chat( + request=CreateChatPromptRequest( name="name", prompt=[ - ChatMessageWithPlaceholders_Chatmessage( + ChatMessage( role="role", content="content", ), - ChatMessageWithPlaceholders_Chatmessage( + ChatMessage( role="role", content="content", ), ], + type="chat", ), ) """ @@ -431,10 +429,7 @@ async def create( import asyncio from langfuse import AsyncLangfuseAPI - from langfuse.prompts import ( - ChatMessageWithPlaceholders_Chatmessage, - CreatePromptRequest_Chat, - ) + from langfuse.prompts import ChatMessage, CreateChatPromptRequest client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -448,18 +443,19 @@ async def create( async def main() -> None: await client.prompts.create( - request=CreatePromptRequest_Chat( + request=CreateChatPromptRequest( name="name", prompt=[ - ChatMessageWithPlaceholders_Chatmessage( + ChatMessage( role="role", content="content", ), - ChatMessageWithPlaceholders_Chatmessage( + ChatMessage( role="role", content="content", ), ], + type="chat", ), ) diff --git a/langfuse/api/prompts/types/__init__.py b/langfuse/api/prompts/types/__init__.py index fbe81d8cd..6522163be 100644 --- a/langfuse/api/prompts/types/__init__.py +++ b/langfuse/api/prompts/types/__init__.py @@ -8,19 +8,13 @@ if typing.TYPE_CHECKING: from .base_prompt import BasePrompt from .chat_message import ChatMessage - from .chat_message_with_placeholders import ( - ChatMessageWithPlaceholders, - ChatMessageWithPlaceholders_Chatmessage, - ChatMessageWithPlaceholders_Placeholder, - ) + from .chat_message_with_placeholders import ChatMessageWithPlaceholders from .chat_prompt import ChatPrompt from .create_chat_prompt_request import CreateChatPromptRequest - from .create_prompt_request import ( - CreatePromptRequest, - CreatePromptRequest_Chat, - CreatePromptRequest_Text, - ) + from .create_chat_prompt_type import CreateChatPromptType + from .create_prompt_request import CreatePromptRequest from .create_text_prompt_request import CreateTextPromptRequest + from .create_text_prompt_type import CreateTextPromptType from .placeholder_message import PlaceholderMessage from .prompt import Prompt, Prompt_Chat, Prompt_Text from .prompt_meta import PromptMeta @@ -31,14 +25,12 @@ "BasePrompt": ".base_prompt", "ChatMessage": ".chat_message", "ChatMessageWithPlaceholders": ".chat_message_with_placeholders", - "ChatMessageWithPlaceholders_Chatmessage": ".chat_message_with_placeholders", - "ChatMessageWithPlaceholders_Placeholder": ".chat_message_with_placeholders", "ChatPrompt": ".chat_prompt", "CreateChatPromptRequest": ".create_chat_prompt_request", + "CreateChatPromptType": ".create_chat_prompt_type", "CreatePromptRequest": ".create_prompt_request", - "CreatePromptRequest_Chat": ".create_prompt_request", - "CreatePromptRequest_Text": ".create_prompt_request", "CreateTextPromptRequest": ".create_text_prompt_request", + "CreateTextPromptType": ".create_text_prompt_type", "PlaceholderMessage": ".placeholder_message", "Prompt": ".prompt", "PromptMeta": ".prompt_meta", @@ -81,14 +73,12 @@ def __dir__(): "BasePrompt", "ChatMessage", "ChatMessageWithPlaceholders", - "ChatMessageWithPlaceholders_Chatmessage", - "ChatMessageWithPlaceholders_Placeholder", "ChatPrompt", "CreateChatPromptRequest", + "CreateChatPromptType", "CreatePromptRequest", - "CreatePromptRequest_Chat", - "CreatePromptRequest_Text", "CreateTextPromptRequest", + "CreateTextPromptType", "PlaceholderMessage", "Prompt", "PromptMeta", diff --git a/langfuse/api/prompts/types/chat_message_with_placeholders.py b/langfuse/api/prompts/types/chat_message_with_placeholders.py index 7e05fd76f..e077ca144 100644 --- a/langfuse/api/prompts/types/chat_message_with_placeholders.py +++ b/langfuse/api/prompts/types/chat_message_with_placeholders.py @@ -1,50 +1,8 @@ # This file was auto-generated by Fern from our API Definition. -from __future__ import annotations - import typing -import pydantic -import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel - - -class ChatMessageWithPlaceholders_Chatmessage(UniversalBaseModel): - type: typing.Literal["chatmessage"] = "chatmessage" - role: str - content: str - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow - - -class ChatMessageWithPlaceholders_Placeholder(UniversalBaseModel): - type: typing.Literal["placeholder"] = "placeholder" - name: str - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow - +from .chat_message import ChatMessage +from .placeholder_message import PlaceholderMessage -ChatMessageWithPlaceholders = typing_extensions.Annotated[ - typing.Union[ - ChatMessageWithPlaceholders_Chatmessage, ChatMessageWithPlaceholders_Placeholder - ], - pydantic.Field(discriminator="type"), -] +ChatMessageWithPlaceholders = typing.Union[ChatMessage, PlaceholderMessage] diff --git a/langfuse/api/prompts/types/create_chat_prompt_request.py b/langfuse/api/prompts/types/create_chat_prompt_request.py index 8ddc2a946..041c3deb2 100644 --- a/langfuse/api/prompts/types/create_chat_prompt_request.py +++ b/langfuse/api/prompts/types/create_chat_prompt_request.py @@ -7,12 +7,14 @@ from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel from ...core.serialization import FieldMetadata from .chat_message_with_placeholders import ChatMessageWithPlaceholders +from .create_chat_prompt_type import CreateChatPromptType class CreateChatPromptRequest(UniversalBaseModel): name: str prompt: typing.List[ChatMessageWithPlaceholders] config: typing.Optional[typing.Any] = None + type: CreateChatPromptType labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) """ List of deployment labels of this prompt version. diff --git a/langfuse/api/prompts/types/create_chat_prompt_type.py b/langfuse/api/prompts/types/create_chat_prompt_type.py new file mode 100644 index 000000000..66bb234f8 --- /dev/null +++ b/langfuse/api/prompts/types/create_chat_prompt_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CreateChatPromptType = typing.Union[typing.Literal["chat"], typing.Any] diff --git a/langfuse/api/prompts/types/create_prompt_request.py b/langfuse/api/prompts/types/create_prompt_request.py index 8c144871e..13d75e7e1 100644 --- a/langfuse/api/prompts/types/create_prompt_request.py +++ b/langfuse/api/prompts/types/create_prompt_request.py @@ -1,63 +1,8 @@ # This file was auto-generated by Fern from our API Definition. -from __future__ import annotations - import typing -import pydantic -import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel -from ...core.serialization import FieldMetadata -from .chat_message_with_placeholders import ChatMessageWithPlaceholders - - -class CreatePromptRequest_Chat(UniversalBaseModel): - type: typing.Literal["chat"] = "chat" - name: str - prompt: typing.List[ChatMessageWithPlaceholders] - config: typing.Optional[typing.Any] = None - labels: typing.Optional[typing.List[str]] = None - tags: typing.Optional[typing.List[str]] = None - commit_message: typing_extensions.Annotated[ - typing.Optional[str], FieldMetadata(alias="commitMessage") - ] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow - - -class CreatePromptRequest_Text(UniversalBaseModel): - type: typing.Literal["text"] = "text" - name: str - prompt: str - config: typing.Optional[typing.Any] = None - labels: typing.Optional[typing.List[str]] = None - tags: typing.Optional[typing.List[str]] = None - commit_message: typing_extensions.Annotated[ - typing.Optional[str], FieldMetadata(alias="commitMessage") - ] = None - - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow - +from .create_chat_prompt_request import CreateChatPromptRequest +from .create_text_prompt_request import CreateTextPromptRequest -CreatePromptRequest = typing_extensions.Annotated[ - typing.Union[CreatePromptRequest_Chat, CreatePromptRequest_Text], - pydantic.Field(discriminator="type"), -] +CreatePromptRequest = typing.Union[CreateChatPromptRequest, CreateTextPromptRequest] diff --git a/langfuse/api/prompts/types/create_text_prompt_request.py b/langfuse/api/prompts/types/create_text_prompt_request.py index 12b50cbc7..94d780ef6 100644 --- a/langfuse/api/prompts/types/create_text_prompt_request.py +++ b/langfuse/api/prompts/types/create_text_prompt_request.py @@ -6,12 +6,14 @@ import typing_extensions from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel from ...core.serialization import FieldMetadata +from .create_text_prompt_type import CreateTextPromptType class CreateTextPromptRequest(UniversalBaseModel): name: str prompt: str config: typing.Optional[typing.Any] = None + type: typing.Optional[CreateTextPromptType] = None labels: typing.Optional[typing.List[str]] = pydantic.Field(default=None) """ List of deployment labels of this prompt version. diff --git a/langfuse/api/prompts/types/create_text_prompt_type.py b/langfuse/api/prompts/types/create_text_prompt_type.py new file mode 100644 index 000000000..9229bd220 --- /dev/null +++ b/langfuse/api/prompts/types/create_text_prompt_type.py @@ -0,0 +1,5 @@ +# This file was auto-generated by Fern from our API Definition. + +import typing + +CreateTextPromptType = typing.Union[typing.Literal["text"], typing.Any] diff --git a/tests/test_prompt.py b/tests/test_prompt.py index a4466adb3..5c263d462 100644 --- a/tests/test_prompt.py +++ b/tests/test_prompt.py @@ -10,8 +10,7 @@ PromptCache, PromptCacheItem, ) -from langfuse.api import NotFoundError -from langfuse.api import Prompt_Chat, Prompt_Text +from langfuse.api import NotFoundError, Prompt_Chat, Prompt_Text from langfuse.model import ChatPromptClient, TextPromptClient from tests.utils import create_uuid, get_api @@ -706,7 +705,7 @@ def test_get_fresh_prompt(langfuse): tags=[], ) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result = langfuse.get_prompt(prompt_name, fallback="fallback") @@ -734,7 +733,7 @@ def test_throw_if_name_unspecified(langfuse): def test_throw_when_failing_fetch_and_no_cache(langfuse): prompt_name = "failing_fetch_and_no_cache" - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.side_effect = Exception("Prompt not found") with pytest.raises(Exception) as exc_info: @@ -755,7 +754,7 @@ def test_using_custom_prompt_timeouts(langfuse): tags=[], ) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result = langfuse.get_prompt( @@ -796,7 +795,7 @@ def test_get_valid_cached_prompt(langfuse): ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name, fallback="fallback") @@ -822,7 +821,7 @@ def test_get_valid_cached_chat_prompt_by_label(langfuse): ) prompt_client = ChatPromptClient(prompt) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name, label="test") @@ -848,7 +847,7 @@ def test_get_valid_cached_chat_prompt_by_version(langfuse): ) prompt_client = ChatPromptClient(prompt) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name, version=1) @@ -874,7 +873,7 @@ def test_get_valid_cached_production_chat_prompt(langfuse): ) prompt_client = ChatPromptClient(prompt) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name) @@ -900,7 +899,7 @@ def test_get_valid_cached_chat_prompt(langfuse): ) prompt_client = ChatPromptClient(prompt) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name) @@ -930,7 +929,7 @@ def test_get_fresh_prompt_when_expired_cache_custom_ttl(mock_time, langfuse: Lan ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name, cache_ttl_seconds=ttl_seconds) @@ -995,7 +994,7 @@ def test_disable_caching_when_ttl_zero(mock_time, langfuse: Langfuse): tags=[], ) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.side_effect = [prompt1, prompt2, prompt3] # First call @@ -1037,7 +1036,7 @@ def test_get_stale_prompt_when_expired_cache_default_ttl(mock_time, langfuse: La ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name) @@ -1099,7 +1098,7 @@ def test_get_fresh_prompt_when_expired_cache_default_ttl(mock_time, langfuse: La ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name) @@ -1143,7 +1142,7 @@ def test_get_expired_prompt_when_failing_fetch(mock_time, langfuse: Langfuse): ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name) @@ -1187,7 +1186,7 @@ def test_evict_prompt_cache_entry_when_refresh_returns_not_found( prompt_client = TextPromptClient(prompt) cache_key = PromptCache.generate_cache_key(prompt_name, version=None, label=None) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt initial_result = langfuse.get_prompt( @@ -1244,7 +1243,7 @@ def test_get_fresh_prompt_when_version_changes(langfuse: Langfuse): ) prompt_client = TextPromptClient(prompt) - mock_server_call = langfuse.api + mock_server_call = langfuse.api.prompts.get mock_server_call.return_value = prompt result_call_1 = langfuse.get_prompt(prompt_name, version=1) From 4130ef47a666c2138cc211c02e13bf486ee0ddb3 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 22 Dec 2025 12:07:41 +0100 Subject: [PATCH 07/15] push --- langfuse/_client/client.py | 6 +- .../_task_manager/score_ingestion_consumer.py | 18 +++--- tests/utils.py | 62 ------------------- 3 files changed, 10 insertions(+), 76 deletions(-) diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py index abb6b2640..e28eb356d 100644 --- a/langfuse/_client/client.py +++ b/langfuse/_client/client.py @@ -2055,14 +2055,14 @@ def create_score( new_body = ScoreBody( id=score_id, session_id=session_id, - dataset_run_id=dataset_run_id, - trace_id=trace_id, + datasetRunId=dataset_run_id, + traceId=trace_id, observation_id=observation_id, name=name, value=value, dataType=data_type, # type: ignore comment=comment, - config_id=config_id, + configId=config_id, environment=self._environment, metadata=metadata, ) diff --git a/langfuse/_task_manager/score_ingestion_consumer.py b/langfuse/_task_manager/score_ingestion_consumer.py index 1a5b61f91..f53ea08f0 100644 --- a/langfuse/_task_manager/score_ingestion_consumer.py +++ b/langfuse/_task_manager/score_ingestion_consumer.py @@ -7,23 +7,19 @@ from typing import Any, List, Optional import backoff - -from ..version import __version__ as langfuse_version - -try: - import pydantic.v1 as pydantic -except ImportError: - import pydantic # type: ignore +from pydantic import BaseModel from langfuse._utils.parse_error import handle_exception from langfuse._utils.request import APIError, LangfuseClient from langfuse._utils.serializer import EventSerializer +from ..version import __version__ as langfuse_version + MAX_EVENT_SIZE_BYTES = int(os.environ.get("LANGFUSE_MAX_EVENT_SIZE_BYTES", 1_000_000)) MAX_BATCH_SIZE_BYTES = int(os.environ.get("LANGFUSE_MAX_BATCH_SIZE_BYTES", 2_500_000)) -class ScoreIngestionMetadata(pydantic.BaseModel): +class ScoreIngestionMetadata(BaseModel): batch_size: int sdk_name: str sdk_version: str @@ -78,8 +74,8 @@ def _next(self) -> list: ) # convert pydantic models to dicts - if "body" in event and isinstance(event["body"], pydantic.BaseModel): - event["body"] = event["body"].dict(exclude_none=True) + if "body" in event and isinstance(event["body"], BaseModel): + event["body"] = event["body"].model_dump(exclude_none=True) item_size = self._get_item_size(event) @@ -156,7 +152,7 @@ def _upload_batch(self, batch: List[Any]) -> None: sdk_name="python", sdk_version=langfuse_version, public_key=self._public_key, - ).dict() + ).model_dump() @backoff.on_exception( backoff.expo, Exception, max_tries=self._max_retries, logger=None diff --git a/tests/utils.py b/tests/utils.py index f42767983..7d6530b45 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,14 +1,8 @@ import base64 import os -import typing from time import sleep from uuid import uuid4 -try: - import pydantic.v1 as pydantic # type: ignore -except ImportError: - import pydantic # type: ignore - from langfuse.api import LangfuseAPI @@ -26,62 +20,6 @@ def get_api(): ) -class LlmUsageWithCost(pydantic.BaseModel): - prompt_tokens: typing.Optional[int] = pydantic.Field( - alias="promptTokens", default=None - ) - completion_tokens: typing.Optional[int] = pydantic.Field( - alias="completionTokens", default=None - ) - total_tokens: typing.Optional[int] = pydantic.Field( - alias="totalTokens", default=None - ) - input_cost: typing.Optional[float] = pydantic.Field(alias="inputCost", default=None) - output_cost: typing.Optional[float] = pydantic.Field( - alias="outputCost", default=None - ) - total_cost: typing.Optional[float] = pydantic.Field(alias="totalCost", default=None) - - -class CompletionUsage(pydantic.BaseModel): - completion_tokens: int - """Number of tokens in the generated completion.""" - - prompt_tokens: int - """Number of tokens in the prompt.""" - - total_tokens: int - """Total number of tokens used in the request (prompt + completion).""" - - -class LlmUsage(pydantic.BaseModel): - prompt_tokens: typing.Optional[int] = pydantic.Field( - alias="promptTokens", default=None - ) - completion_tokens: typing.Optional[int] = pydantic.Field( - alias="completionTokens", default=None - ) - total_tokens: typing.Optional[int] = pydantic.Field( - alias="totalTokens", default=None - ) - - def json(self, **kwargs: typing.Any) -> str: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().json(**kwargs_with_defaults) - - def dict(self, **kwargs: typing.Any) -> typing.Dict[str, typing.Any]: - kwargs_with_defaults: typing.Any = { - "by_alias": True, - "exclude_unset": True, - **kwargs, - } - return super().dict(**kwargs_with_defaults) - - def encode_file_to_base64(image_path) -> str: with open(image_path, "rb") as file: return base64.b64encode(file.read()).decode("utf-8") From b7b16efc47564a7326c351f789c14979a780c33d Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 22 Dec 2025 12:13:18 +0100 Subject: [PATCH 08/15] push --- langfuse/api/commons/types/map_value.py | 1 + 1 file changed, 1 insertion(+) diff --git a/langfuse/api/commons/types/map_value.py b/langfuse/api/commons/types/map_value.py index e1e771a9b..46115a967 100644 --- a/langfuse/api/commons/types/map_value.py +++ b/langfuse/api/commons/types/map_value.py @@ -5,6 +5,7 @@ MapValue = typing.Union[ typing.Optional[str], typing.Optional[int], + typing.Optional[float], typing.Optional[bool], typing.Optional[typing.List[str]], ] From 0cf5f26577d0884ea763bc93d7eb21f3a471e06d Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 22 Dec 2025 12:47:14 +0100 Subject: [PATCH 09/15] push --- .github/workflows/ci.yml | 1 + langfuse/_client/client.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 344225dcb..d4f1b6775 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,7 @@ jobs: - "3.11" - "3.12" - "3.13" + - "3.14" name: Test on Python version ${{ matrix.python-version }} steps: diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py index e28eb356d..09d0076bf 100644 --- a/langfuse/_client/client.py +++ b/langfuse/_client/client.py @@ -2057,7 +2057,7 @@ def create_score( session_id=session_id, datasetRunId=dataset_run_id, traceId=trace_id, - observation_id=observation_id, + observationId=observation_id, name=name, value=value, dataType=data_type, # type: ignore From 7f0d52992c5b115786e93743f94e6afe03ca7140 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 22 Dec 2025 13:03:43 +0100 Subject: [PATCH 10/15] add back enums --- langfuse/_client/client.py | 3 +- langfuse/api/.fern/metadata.json | 3 + langfuse/api/annotation_queues/client.py | 6 +- .../types/annotation_queue_object_type.py | 25 +- .../types/annotation_queue_status.py | 19 +- .../api/blob_storage_integrations/client.py | 28 +- .../types/blob_storage_export_frequency.py | 25 +- .../types/blob_storage_export_mode.py | 25 +- .../blob_storage_integration_file_type.py | 25 +- .../types/blob_storage_integration_type.py | 25 +- .../api/commons/types/comment_object_type.py | 29 +- langfuse/api/commons/types/dataset_status.py | 19 +- .../api/commons/types/model_usage_unit.py | 44 ++- .../api/commons/types/observation_level.py | 29 +- .../commons/types/pricing_tier_operator.py | 41 ++- langfuse/api/commons/types/score_data_type.py | 25 +- langfuse/api/commons/types/score_source.py | 23 +- langfuse/api/core/enum.py | 20 ++ .../api/ingestion/types/observation_type.py | 65 +++- langfuse/api/llm_connections/client.py | 6 +- .../api/llm_connections/types/llm_adapter.py | 45 ++- langfuse/api/media/client.py | 6 +- .../api/media/types/media_content_type.py | 285 ++++++++++++++---- langfuse/api/organizations/client.py | 12 +- .../organizations/types/membership_role.py | 29 +- langfuse/api/prompts/client.py | 16 +- .../prompts/types/create_chat_prompt_type.py | 12 +- .../prompts/types/create_text_prompt_type.py | 12 +- langfuse/api/prompts/types/prompt_type.py | 17 +- langfuse/api/score_configs/client.py | 6 +- 30 files changed, 775 insertions(+), 150 deletions(-) create mode 100644 langfuse/api/core/enum.py diff --git a/langfuse/_client/client.py b/langfuse/_client/client.py index 09d0076bf..3a2578146 100644 --- a/langfuse/_client/client.py +++ b/langfuse/_client/client.py @@ -80,6 +80,7 @@ from langfuse._utils.prompt_cache import PromptCache from langfuse.api import ( CreateChatPromptRequest, + CreateChatPromptType, CreateTextPromptRequest, Dataset, DatasetItem, @@ -3710,7 +3711,7 @@ def create_prompt( tags=tags, config=config or {}, commit_message=commit_message, - type="chat", + type=CreateChatPromptType.CHAT, ) ) server_prompt = self.api.prompts.create(request=request) diff --git a/langfuse/api/.fern/metadata.json b/langfuse/api/.fern/metadata.json index e1ced29c9..8bf3385f7 100644 --- a/langfuse/api/.fern/metadata.json +++ b/langfuse/api/.fern/metadata.json @@ -3,6 +3,9 @@ "generatorName": "fernapi/fern-python-sdk", "generatorVersion": "4.46.2", "generatorConfig": { + "pydantic_config": { + "enum_type": "python_enums" + }, "client": { "class_name": "LangfuseAPI" } diff --git a/langfuse/api/annotation_queues/client.py b/langfuse/api/annotation_queues/client.py index e4ab29173..6fb3d5682 100644 --- a/langfuse/api/annotation_queues/client.py +++ b/langfuse/api/annotation_queues/client.py @@ -313,6 +313,7 @@ def create_queue_item( Examples -------- from langfuse import LangfuseAPI + from langfuse.annotation_queues import AnnotationQueueObjectType client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -325,7 +326,7 @@ def create_queue_item( client.annotation_queues.create_queue_item( queue_id="queueId", object_id="objectId", - object_type="TRACE", + object_type=AnnotationQueueObjectType.TRACE, ) """ _response = self._raw_client.create_queue_item( @@ -857,6 +858,7 @@ async def create_queue_item( import asyncio from langfuse import AsyncLangfuseAPI + from langfuse.annotation_queues import AnnotationQueueObjectType client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -872,7 +874,7 @@ async def main() -> None: await client.annotation_queues.create_queue_item( queue_id="queueId", object_id="objectId", - object_type="TRACE", + object_type=AnnotationQueueObjectType.TRACE, ) diff --git a/langfuse/api/annotation_queues/types/annotation_queue_object_type.py b/langfuse/api/annotation_queues/types/annotation_queue_object_type.py index 8f95334b0..af8b95e89 100644 --- a/langfuse/api/annotation_queues/types/annotation_queue_object_type.py +++ b/langfuse/api/annotation_queues/types/annotation_queue_object_type.py @@ -2,6 +2,25 @@ import typing -AnnotationQueueObjectType = typing.Union[ - typing.Literal["TRACE", "OBSERVATION", "SESSION"], typing.Any -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class AnnotationQueueObjectType(enum.StrEnum): + TRACE = "TRACE" + OBSERVATION = "OBSERVATION" + SESSION = "SESSION" + + def visit( + self, + trace: typing.Callable[[], T_Result], + observation: typing.Callable[[], T_Result], + session: typing.Callable[[], T_Result], + ) -> T_Result: + if self is AnnotationQueueObjectType.TRACE: + return trace() + if self is AnnotationQueueObjectType.OBSERVATION: + return observation() + if self is AnnotationQueueObjectType.SESSION: + return session() diff --git a/langfuse/api/annotation_queues/types/annotation_queue_status.py b/langfuse/api/annotation_queues/types/annotation_queue_status.py index 0a732adbc..a11fe3ea8 100644 --- a/langfuse/api/annotation_queues/types/annotation_queue_status.py +++ b/langfuse/api/annotation_queues/types/annotation_queue_status.py @@ -2,4 +2,21 @@ import typing -AnnotationQueueStatus = typing.Union[typing.Literal["PENDING", "COMPLETED"], typing.Any] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class AnnotationQueueStatus(enum.StrEnum): + PENDING = "PENDING" + COMPLETED = "COMPLETED" + + def visit( + self, + pending: typing.Callable[[], T_Result], + completed: typing.Callable[[], T_Result], + ) -> T_Result: + if self is AnnotationQueueStatus.PENDING: + return pending() + if self is AnnotationQueueStatus.COMPLETED: + return completed() diff --git a/langfuse/api/blob_storage_integrations/client.py b/langfuse/api/blob_storage_integrations/client.py index 3833cca57..6b1f6a677 100644 --- a/langfuse/api/blob_storage_integrations/client.py +++ b/langfuse/api/blob_storage_integrations/client.py @@ -146,6 +146,12 @@ def upsert_blob_storage_integration( Examples -------- from langfuse import LangfuseAPI + from langfuse.blob_storage_integrations import ( + BlobStorageExportFrequency, + BlobStorageExportMode, + BlobStorageIntegrationFileType, + BlobStorageIntegrationType, + ) client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -157,14 +163,14 @@ def upsert_blob_storage_integration( ) client.blob_storage_integrations.upsert_blob_storage_integration( project_id="projectId", - type="S3", + type=BlobStorageIntegrationType.S3, bucket_name="bucketName", region="region", - export_frequency="hourly", + export_frequency=BlobStorageExportFrequency.HOURLY, enabled=True, force_path_style=True, - file_type="JSON", - export_mode="FULL_HISTORY", + file_type=BlobStorageIntegrationFileType.JSON, + export_mode=BlobStorageExportMode.FULL_HISTORY, ) """ _response = self._raw_client.upsert_blob_storage_integration( @@ -358,6 +364,12 @@ async def upsert_blob_storage_integration( import asyncio from langfuse import AsyncLangfuseAPI + from langfuse.blob_storage_integrations import ( + BlobStorageExportFrequency, + BlobStorageExportMode, + BlobStorageIntegrationFileType, + BlobStorageIntegrationType, + ) client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -372,14 +384,14 @@ async def upsert_blob_storage_integration( async def main() -> None: await client.blob_storage_integrations.upsert_blob_storage_integration( project_id="projectId", - type="S3", + type=BlobStorageIntegrationType.S3, bucket_name="bucketName", region="region", - export_frequency="hourly", + export_frequency=BlobStorageExportFrequency.HOURLY, enabled=True, force_path_style=True, - file_type="JSON", - export_mode="FULL_HISTORY", + file_type=BlobStorageIntegrationFileType.JSON, + export_mode=BlobStorageExportMode.FULL_HISTORY, ) diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_export_frequency.py b/langfuse/api/blob_storage_integrations/types/blob_storage_export_frequency.py index a7307c30e..bcc7fc6d5 100644 --- a/langfuse/api/blob_storage_integrations/types/blob_storage_export_frequency.py +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_export_frequency.py @@ -2,6 +2,25 @@ import typing -BlobStorageExportFrequency = typing.Union[ - typing.Literal["hourly", "daily", "weekly"], typing.Any -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class BlobStorageExportFrequency(enum.StrEnum): + HOURLY = "hourly" + DAILY = "daily" + WEEKLY = "weekly" + + def visit( + self, + hourly: typing.Callable[[], T_Result], + daily: typing.Callable[[], T_Result], + weekly: typing.Callable[[], T_Result], + ) -> T_Result: + if self is BlobStorageExportFrequency.HOURLY: + return hourly() + if self is BlobStorageExportFrequency.DAILY: + return daily() + if self is BlobStorageExportFrequency.WEEKLY: + return weekly() diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_export_mode.py b/langfuse/api/blob_storage_integrations/types/blob_storage_export_mode.py index f1b1d95a3..d692c0fb9 100644 --- a/langfuse/api/blob_storage_integrations/types/blob_storage_export_mode.py +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_export_mode.py @@ -2,6 +2,25 @@ import typing -BlobStorageExportMode = typing.Union[ - typing.Literal["FULL_HISTORY", "FROM_TODAY", "FROM_CUSTOM_DATE"], typing.Any -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class BlobStorageExportMode(enum.StrEnum): + FULL_HISTORY = "FULL_HISTORY" + FROM_TODAY = "FROM_TODAY" + FROM_CUSTOM_DATE = "FROM_CUSTOM_DATE" + + def visit( + self, + full_history: typing.Callable[[], T_Result], + from_today: typing.Callable[[], T_Result], + from_custom_date: typing.Callable[[], T_Result], + ) -> T_Result: + if self is BlobStorageExportMode.FULL_HISTORY: + return full_history() + if self is BlobStorageExportMode.FROM_TODAY: + return from_today() + if self is BlobStorageExportMode.FROM_CUSTOM_DATE: + return from_custom_date() diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_file_type.py b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_file_type.py index 09e8762ab..52998e5e4 100644 --- a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_file_type.py +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_file_type.py @@ -2,6 +2,25 @@ import typing -BlobStorageIntegrationFileType = typing.Union[ - typing.Literal["JSON", "CSV", "JSONL"], typing.Any -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class BlobStorageIntegrationFileType(enum.StrEnum): + JSON = "JSON" + CSV = "CSV" + JSONL = "JSONL" + + def visit( + self, + json: typing.Callable[[], T_Result], + csv: typing.Callable[[], T_Result], + jsonl: typing.Callable[[], T_Result], + ) -> T_Result: + if self is BlobStorageIntegrationFileType.JSON: + return json() + if self is BlobStorageIntegrationFileType.CSV: + return csv() + if self is BlobStorageIntegrationFileType.JSONL: + return jsonl() diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_type.py b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_type.py index 0df026d37..66828a62d 100644 --- a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_type.py +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_type.py @@ -2,6 +2,25 @@ import typing -BlobStorageIntegrationType = typing.Union[ - typing.Literal["S3", "S3_COMPATIBLE", "AZURE_BLOB_STORAGE"], typing.Any -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class BlobStorageIntegrationType(enum.StrEnum): + S3 = "S3" + S3COMPATIBLE = "S3_COMPATIBLE" + AZURE_BLOB_STORAGE = "AZURE_BLOB_STORAGE" + + def visit( + self, + s3: typing.Callable[[], T_Result], + s3compatible: typing.Callable[[], T_Result], + azure_blob_storage: typing.Callable[[], T_Result], + ) -> T_Result: + if self is BlobStorageIntegrationType.S3: + return s3() + if self is BlobStorageIntegrationType.S3COMPATIBLE: + return s3compatible() + if self is BlobStorageIntegrationType.AZURE_BLOB_STORAGE: + return azure_blob_storage() diff --git a/langfuse/api/commons/types/comment_object_type.py b/langfuse/api/commons/types/comment_object_type.py index 9677c4293..fbd0d4e49 100644 --- a/langfuse/api/commons/types/comment_object_type.py +++ b/langfuse/api/commons/types/comment_object_type.py @@ -2,6 +2,29 @@ import typing -CommentObjectType = typing.Union[ - typing.Literal["TRACE", "OBSERVATION", "SESSION", "PROMPT"], typing.Any -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class CommentObjectType(enum.StrEnum): + TRACE = "TRACE" + OBSERVATION = "OBSERVATION" + SESSION = "SESSION" + PROMPT = "PROMPT" + + def visit( + self, + trace: typing.Callable[[], T_Result], + observation: typing.Callable[[], T_Result], + session: typing.Callable[[], T_Result], + prompt: typing.Callable[[], T_Result], + ) -> T_Result: + if self is CommentObjectType.TRACE: + return trace() + if self is CommentObjectType.OBSERVATION: + return observation() + if self is CommentObjectType.SESSION: + return session() + if self is CommentObjectType.PROMPT: + return prompt() diff --git a/langfuse/api/commons/types/dataset_status.py b/langfuse/api/commons/types/dataset_status.py index f09c011d2..f8e681aeb 100644 --- a/langfuse/api/commons/types/dataset_status.py +++ b/langfuse/api/commons/types/dataset_status.py @@ -2,4 +2,21 @@ import typing -DatasetStatus = typing.Union[typing.Literal["ACTIVE", "ARCHIVED"], typing.Any] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class DatasetStatus(enum.StrEnum): + ACTIVE = "ACTIVE" + ARCHIVED = "ARCHIVED" + + def visit( + self, + active: typing.Callable[[], T_Result], + archived: typing.Callable[[], T_Result], + ) -> T_Result: + if self is DatasetStatus.ACTIVE: + return active() + if self is DatasetStatus.ARCHIVED: + return archived() diff --git a/langfuse/api/commons/types/model_usage_unit.py b/langfuse/api/commons/types/model_usage_unit.py index 6705b47e3..281223960 100644 --- a/langfuse/api/commons/types/model_usage_unit.py +++ b/langfuse/api/commons/types/model_usage_unit.py @@ -2,9 +2,41 @@ import typing -ModelUsageUnit = typing.Union[ - typing.Literal[ - "CHARACTERS", "TOKENS", "MILLISECONDS", "SECONDS", "IMAGES", "REQUESTS" - ], - typing.Any, -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class ModelUsageUnit(enum.StrEnum): + """ + Unit of usage in Langfuse + """ + + CHARACTERS = "CHARACTERS" + TOKENS = "TOKENS" + MILLISECONDS = "MILLISECONDS" + SECONDS = "SECONDS" + IMAGES = "IMAGES" + REQUESTS = "REQUESTS" + + def visit( + self, + characters: typing.Callable[[], T_Result], + tokens: typing.Callable[[], T_Result], + milliseconds: typing.Callable[[], T_Result], + seconds: typing.Callable[[], T_Result], + images: typing.Callable[[], T_Result], + requests: typing.Callable[[], T_Result], + ) -> T_Result: + if self is ModelUsageUnit.CHARACTERS: + return characters() + if self is ModelUsageUnit.TOKENS: + return tokens() + if self is ModelUsageUnit.MILLISECONDS: + return milliseconds() + if self is ModelUsageUnit.SECONDS: + return seconds() + if self is ModelUsageUnit.IMAGES: + return images() + if self is ModelUsageUnit.REQUESTS: + return requests() diff --git a/langfuse/api/commons/types/observation_level.py b/langfuse/api/commons/types/observation_level.py index 8a42779ca..8629ef31d 100644 --- a/langfuse/api/commons/types/observation_level.py +++ b/langfuse/api/commons/types/observation_level.py @@ -2,6 +2,29 @@ import typing -ObservationLevel = typing.Union[ - typing.Literal["DEBUG", "DEFAULT", "WARNING", "ERROR"], typing.Any -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class ObservationLevel(enum.StrEnum): + DEBUG = "DEBUG" + DEFAULT = "DEFAULT" + WARNING = "WARNING" + ERROR = "ERROR" + + def visit( + self, + debug: typing.Callable[[], T_Result], + default: typing.Callable[[], T_Result], + warning: typing.Callable[[], T_Result], + error: typing.Callable[[], T_Result], + ) -> T_Result: + if self is ObservationLevel.DEBUG: + return debug() + if self is ObservationLevel.DEFAULT: + return default() + if self is ObservationLevel.WARNING: + return warning() + if self is ObservationLevel.ERROR: + return error() diff --git a/langfuse/api/commons/types/pricing_tier_operator.py b/langfuse/api/commons/types/pricing_tier_operator.py index 14d4a80eb..6d40799ec 100644 --- a/langfuse/api/commons/types/pricing_tier_operator.py +++ b/langfuse/api/commons/types/pricing_tier_operator.py @@ -2,6 +2,41 @@ import typing -PricingTierOperator = typing.Union[ - typing.Literal["gt", "gte", "lt", "lte", "eq", "neq"], typing.Any -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class PricingTierOperator(enum.StrEnum): + """ + Comparison operators for pricing tier conditions + """ + + GT = "gt" + GTE = "gte" + LT = "lt" + LTE = "lte" + EQ = "eq" + NEQ = "neq" + + def visit( + self, + gt: typing.Callable[[], T_Result], + gte: typing.Callable[[], T_Result], + lt: typing.Callable[[], T_Result], + lte: typing.Callable[[], T_Result], + eq: typing.Callable[[], T_Result], + neq: typing.Callable[[], T_Result], + ) -> T_Result: + if self is PricingTierOperator.GT: + return gt() + if self is PricingTierOperator.GTE: + return gte() + if self is PricingTierOperator.LT: + return lt() + if self is PricingTierOperator.LTE: + return lte() + if self is PricingTierOperator.EQ: + return eq() + if self is PricingTierOperator.NEQ: + return neq() diff --git a/langfuse/api/commons/types/score_data_type.py b/langfuse/api/commons/types/score_data_type.py index d3be48c06..a94d68d7c 100644 --- a/langfuse/api/commons/types/score_data_type.py +++ b/langfuse/api/commons/types/score_data_type.py @@ -2,6 +2,25 @@ import typing -ScoreDataType = typing.Union[ - typing.Literal["NUMERIC", "BOOLEAN", "CATEGORICAL"], typing.Any -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class ScoreDataType(enum.StrEnum): + NUMERIC = "NUMERIC" + BOOLEAN = "BOOLEAN" + CATEGORICAL = "CATEGORICAL" + + def visit( + self, + numeric: typing.Callable[[], T_Result], + boolean: typing.Callable[[], T_Result], + categorical: typing.Callable[[], T_Result], + ) -> T_Result: + if self is ScoreDataType.NUMERIC: + return numeric() + if self is ScoreDataType.BOOLEAN: + return boolean() + if self is ScoreDataType.CATEGORICAL: + return categorical() diff --git a/langfuse/api/commons/types/score_source.py b/langfuse/api/commons/types/score_source.py index 036918272..ee1398a9a 100644 --- a/langfuse/api/commons/types/score_source.py +++ b/langfuse/api/commons/types/score_source.py @@ -2,4 +2,25 @@ import typing -ScoreSource = typing.Union[typing.Literal["ANNOTATION", "API", "EVAL"], typing.Any] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class ScoreSource(enum.StrEnum): + ANNOTATION = "ANNOTATION" + API = "API" + EVAL = "EVAL" + + def visit( + self, + annotation: typing.Callable[[], T_Result], + api: typing.Callable[[], T_Result], + eval: typing.Callable[[], T_Result], + ) -> T_Result: + if self is ScoreSource.ANNOTATION: + return annotation() + if self is ScoreSource.API: + return api() + if self is ScoreSource.EVAL: + return eval() diff --git a/langfuse/api/core/enum.py b/langfuse/api/core/enum.py new file mode 100644 index 000000000..a3d17a67b --- /dev/null +++ b/langfuse/api/core/enum.py @@ -0,0 +1,20 @@ +# This file was auto-generated by Fern from our API Definition. + +""" +Provides a StrEnum base class that works across Python versions. + +For Python >= 3.11, this re-exports the standard library enum.StrEnum. +For older Python versions, this defines a compatible StrEnum using the +(str, Enum) mixin pattern so that generated SDKs can use a single base +class in all supported Python versions. +""" + +import enum +import sys + +if sys.version_info >= (3, 11): + from enum import StrEnum +else: + + class StrEnum(str, enum.Enum): + pass diff --git a/langfuse/api/ingestion/types/observation_type.py b/langfuse/api/ingestion/types/observation_type.py index eb6079ba7..f769e34cf 100644 --- a/langfuse/api/ingestion/types/observation_type.py +++ b/langfuse/api/ingestion/types/observation_type.py @@ -2,18 +2,53 @@ import typing -ObservationType = typing.Union[ - typing.Literal[ - "SPAN", - "GENERATION", - "EVENT", - "AGENT", - "TOOL", - "CHAIN", - "RETRIEVER", - "EVALUATOR", - "EMBEDDING", - "GUARDRAIL", - ], - typing.Any, -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class ObservationType(enum.StrEnum): + SPAN = "SPAN" + GENERATION = "GENERATION" + EVENT = "EVENT" + AGENT = "AGENT" + TOOL = "TOOL" + CHAIN = "CHAIN" + RETRIEVER = "RETRIEVER" + EVALUATOR = "EVALUATOR" + EMBEDDING = "EMBEDDING" + GUARDRAIL = "GUARDRAIL" + + def visit( + self, + span: typing.Callable[[], T_Result], + generation: typing.Callable[[], T_Result], + event: typing.Callable[[], T_Result], + agent: typing.Callable[[], T_Result], + tool: typing.Callable[[], T_Result], + chain: typing.Callable[[], T_Result], + retriever: typing.Callable[[], T_Result], + evaluator: typing.Callable[[], T_Result], + embedding: typing.Callable[[], T_Result], + guardrail: typing.Callable[[], T_Result], + ) -> T_Result: + if self is ObservationType.SPAN: + return span() + if self is ObservationType.GENERATION: + return generation() + if self is ObservationType.EVENT: + return event() + if self is ObservationType.AGENT: + return agent() + if self is ObservationType.TOOL: + return tool() + if self is ObservationType.CHAIN: + return chain() + if self is ObservationType.RETRIEVER: + return retriever() + if self is ObservationType.EVALUATOR: + return evaluator() + if self is ObservationType.EMBEDDING: + return embedding() + if self is ObservationType.GUARDRAIL: + return guardrail() diff --git a/langfuse/api/llm_connections/client.py b/langfuse/api/llm_connections/client.py index 5fcc6b8a7..213e55e9f 100644 --- a/langfuse/api/llm_connections/client.py +++ b/langfuse/api/llm_connections/client.py @@ -124,6 +124,7 @@ def upsert( Examples -------- from langfuse import LangfuseAPI + from langfuse.llm_connections import LlmAdapter client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -135,7 +136,7 @@ def upsert( ) client.llm_connections.upsert( provider="provider", - adapter="anthropic", + adapter=LlmAdapter.ANTHROPIC, secret_key="secretKey", ) """ @@ -274,6 +275,7 @@ async def upsert( import asyncio from langfuse import AsyncLangfuseAPI + from langfuse.llm_connections import LlmAdapter client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -288,7 +290,7 @@ async def upsert( async def main() -> None: await client.llm_connections.upsert( provider="provider", - adapter="anthropic", + adapter=LlmAdapter.ANTHROPIC, secret_key="secretKey", ) diff --git a/langfuse/api/llm_connections/types/llm_adapter.py b/langfuse/api/llm_connections/types/llm_adapter.py index 51470bf1d..08cab5cb9 100644 --- a/langfuse/api/llm_connections/types/llm_adapter.py +++ b/langfuse/api/llm_connections/types/llm_adapter.py @@ -2,14 +2,37 @@ import typing -LlmAdapter = typing.Union[ - typing.Literal[ - "anthropic", - "openai", - "azure", - "bedrock", - "google-vertex-ai", - "google-ai-studio", - ], - typing.Any, -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class LlmAdapter(enum.StrEnum): + ANTHROPIC = "anthropic" + OPEN_AI = "openai" + AZURE = "azure" + BEDROCK = "bedrock" + GOOGLE_VERTEX_AI = "google-vertex-ai" + GOOGLE_AI_STUDIO = "google-ai-studio" + + def visit( + self, + anthropic: typing.Callable[[], T_Result], + open_ai: typing.Callable[[], T_Result], + azure: typing.Callable[[], T_Result], + bedrock: typing.Callable[[], T_Result], + google_vertex_ai: typing.Callable[[], T_Result], + google_ai_studio: typing.Callable[[], T_Result], + ) -> T_Result: + if self is LlmAdapter.ANTHROPIC: + return anthropic() + if self is LlmAdapter.OPEN_AI: + return open_ai() + if self is LlmAdapter.AZURE: + return azure() + if self is LlmAdapter.BEDROCK: + return bedrock() + if self is LlmAdapter.GOOGLE_VERTEX_AI: + return google_vertex_ai() + if self is LlmAdapter.GOOGLE_AI_STUDIO: + return google_ai_studio() diff --git a/langfuse/api/media/client.py b/langfuse/api/media/client.py index 3665a9366..b22272b92 100644 --- a/langfuse/api/media/client.py +++ b/langfuse/api/media/client.py @@ -178,6 +178,7 @@ def get_upload_url( Examples -------- from langfuse import LangfuseAPI + from langfuse.media import MediaContentType client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -189,7 +190,7 @@ def get_upload_url( ) client.media.get_upload_url( trace_id="traceId", - content_type="image/png", + content_type=MediaContentType.IMAGE_PNG, content_length=1, sha256hash="sha256Hash", field="field", @@ -390,6 +391,7 @@ async def get_upload_url( import asyncio from langfuse import AsyncLangfuseAPI + from langfuse.media import MediaContentType client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -404,7 +406,7 @@ async def get_upload_url( async def main() -> None: await client.media.get_upload_url( trace_id="traceId", - content_type="image/png", + content_type=MediaContentType.IMAGE_PNG, content_length=1, sha256hash="sha256Hash", field="field", diff --git a/langfuse/api/media/types/media_content_type.py b/langfuse/api/media/types/media_content_type.py index 0995269ab..9fb5507bc 100644 --- a/langfuse/api/media/types/media_content_type.py +++ b/langfuse/api/media/types/media_content_type.py @@ -2,60 +2,231 @@ import typing -MediaContentType = typing.Union[ - typing.Literal[ - "image/png", - "image/jpeg", - "image/jpg", - "image/webp", - "image/gif", - "image/svg+xml", - "image/tiff", - "image/bmp", - "image/avif", - "image/heic", - "audio/mpeg", - "audio/mp3", - "audio/wav", - "audio/ogg", - "audio/oga", - "audio/aac", - "audio/mp4", - "audio/flac", - "audio/opus", - "audio/webm", - "video/mp4", - "video/webm", - "video/ogg", - "video/mpeg", - "video/quicktime", - "video/x-msvideo", - "video/x-matroska", - "text/plain", - "text/html", - "text/css", - "text/csv", - "text/markdown", - "text/x-python", - "application/javascript", - "text/x-typescript", - "application/x-yaml", - "application/pdf", - "application/msword", - "application/vnd.ms-excel", - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - "application/zip", - "application/json", - "application/xml", - "application/octet-stream", - "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - "application/vnd.openxmlformats-officedocument.presentationml.presentation", - "application/rtf", - "application/x-ndjson", - "application/vnd.apache.parquet", - "application/gzip", - "application/x-tar", - "application/x-7z-compressed", - ], - typing.Any, -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class MediaContentType(enum.StrEnum): + """ + The MIME type of the media record + """ + + IMAGE_PNG = "image/png" + IMAGE_JPEG = "image/jpeg" + IMAGE_JPG = "image/jpg" + IMAGE_WEBP = "image/webp" + IMAGE_GIF = "image/gif" + IMAGE_SVG_XML = "image/svg+xml" + IMAGE_TIFF = "image/tiff" + IMAGE_BMP = "image/bmp" + IMAGE_AVIF = "image/avif" + IMAGE_HEIC = "image/heic" + AUDIO_MPEG = "audio/mpeg" + AUDIO_MP3 = "audio/mp3" + AUDIO_WAV = "audio/wav" + AUDIO_OGG = "audio/ogg" + AUDIO_OGA = "audio/oga" + AUDIO_AAC = "audio/aac" + AUDIO_MP4 = "audio/mp4" + AUDIO_FLAC = "audio/flac" + AUDIO_OPUS = "audio/opus" + AUDIO_WEBM = "audio/webm" + VIDEO_MP4 = "video/mp4" + VIDEO_WEBM = "video/webm" + VIDEO_OGG = "video/ogg" + VIDEO_MPEG = "video/mpeg" + VIDEO_QUICKTIME = "video/quicktime" + VIDEO_X_MSVIDEO = "video/x-msvideo" + VIDEO_X_MATROSKA = "video/x-matroska" + TEXT_PLAIN = "text/plain" + TEXT_HTML = "text/html" + TEXT_CSS = "text/css" + TEXT_CSV = "text/csv" + TEXT_MARKDOWN = "text/markdown" + TEXT_X_PYTHON = "text/x-python" + APPLICATION_JAVASCRIPT = "application/javascript" + TEXT_X_TYPESCRIPT = "text/x-typescript" + APPLICATION_X_YAML = "application/x-yaml" + APPLICATION_PDF = "application/pdf" + APPLICATION_MSWORD = "application/msword" + APPLICATION_MS_EXCEL = "application/vnd.ms-excel" + APPLICATION_OPENXML_SPREADSHEET = ( + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" + ) + APPLICATION_ZIP = "application/zip" + APPLICATION_JSON = "application/json" + APPLICATION_XML = "application/xml" + APPLICATION_OCTET_STREAM = "application/octet-stream" + APPLICATION_OPENXML_WORD = ( + "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + ) + APPLICATION_OPENXML_PRESENTATION = ( + "application/vnd.openxmlformats-officedocument.presentationml.presentation" + ) + APPLICATION_RTF = "application/rtf" + APPLICATION_X_NDJSON = "application/x-ndjson" + APPLICATION_PARQUET = "application/vnd.apache.parquet" + APPLICATION_GZIP = "application/gzip" + APPLICATION_X_TAR = "application/x-tar" + APPLICATION_X7Z_COMPRESSED = "application/x-7z-compressed" + + def visit( + self, + image_png: typing.Callable[[], T_Result], + image_jpeg: typing.Callable[[], T_Result], + image_jpg: typing.Callable[[], T_Result], + image_webp: typing.Callable[[], T_Result], + image_gif: typing.Callable[[], T_Result], + image_svg_xml: typing.Callable[[], T_Result], + image_tiff: typing.Callable[[], T_Result], + image_bmp: typing.Callable[[], T_Result], + image_avif: typing.Callable[[], T_Result], + image_heic: typing.Callable[[], T_Result], + audio_mpeg: typing.Callable[[], T_Result], + audio_mp3: typing.Callable[[], T_Result], + audio_wav: typing.Callable[[], T_Result], + audio_ogg: typing.Callable[[], T_Result], + audio_oga: typing.Callable[[], T_Result], + audio_aac: typing.Callable[[], T_Result], + audio_mp4: typing.Callable[[], T_Result], + audio_flac: typing.Callable[[], T_Result], + audio_opus: typing.Callable[[], T_Result], + audio_webm: typing.Callable[[], T_Result], + video_mp4: typing.Callable[[], T_Result], + video_webm: typing.Callable[[], T_Result], + video_ogg: typing.Callable[[], T_Result], + video_mpeg: typing.Callable[[], T_Result], + video_quicktime: typing.Callable[[], T_Result], + video_x_msvideo: typing.Callable[[], T_Result], + video_x_matroska: typing.Callable[[], T_Result], + text_plain: typing.Callable[[], T_Result], + text_html: typing.Callable[[], T_Result], + text_css: typing.Callable[[], T_Result], + text_csv: typing.Callable[[], T_Result], + text_markdown: typing.Callable[[], T_Result], + text_x_python: typing.Callable[[], T_Result], + application_javascript: typing.Callable[[], T_Result], + text_x_typescript: typing.Callable[[], T_Result], + application_x_yaml: typing.Callable[[], T_Result], + application_pdf: typing.Callable[[], T_Result], + application_msword: typing.Callable[[], T_Result], + application_ms_excel: typing.Callable[[], T_Result], + application_openxml_spreadsheet: typing.Callable[[], T_Result], + application_zip: typing.Callable[[], T_Result], + application_json: typing.Callable[[], T_Result], + application_xml: typing.Callable[[], T_Result], + application_octet_stream: typing.Callable[[], T_Result], + application_openxml_word: typing.Callable[[], T_Result], + application_openxml_presentation: typing.Callable[[], T_Result], + application_rtf: typing.Callable[[], T_Result], + application_x_ndjson: typing.Callable[[], T_Result], + application_parquet: typing.Callable[[], T_Result], + application_gzip: typing.Callable[[], T_Result], + application_x_tar: typing.Callable[[], T_Result], + application_x7z_compressed: typing.Callable[[], T_Result], + ) -> T_Result: + if self is MediaContentType.IMAGE_PNG: + return image_png() + if self is MediaContentType.IMAGE_JPEG: + return image_jpeg() + if self is MediaContentType.IMAGE_JPG: + return image_jpg() + if self is MediaContentType.IMAGE_WEBP: + return image_webp() + if self is MediaContentType.IMAGE_GIF: + return image_gif() + if self is MediaContentType.IMAGE_SVG_XML: + return image_svg_xml() + if self is MediaContentType.IMAGE_TIFF: + return image_tiff() + if self is MediaContentType.IMAGE_BMP: + return image_bmp() + if self is MediaContentType.IMAGE_AVIF: + return image_avif() + if self is MediaContentType.IMAGE_HEIC: + return image_heic() + if self is MediaContentType.AUDIO_MPEG: + return audio_mpeg() + if self is MediaContentType.AUDIO_MP3: + return audio_mp3() + if self is MediaContentType.AUDIO_WAV: + return audio_wav() + if self is MediaContentType.AUDIO_OGG: + return audio_ogg() + if self is MediaContentType.AUDIO_OGA: + return audio_oga() + if self is MediaContentType.AUDIO_AAC: + return audio_aac() + if self is MediaContentType.AUDIO_MP4: + return audio_mp4() + if self is MediaContentType.AUDIO_FLAC: + return audio_flac() + if self is MediaContentType.AUDIO_OPUS: + return audio_opus() + if self is MediaContentType.AUDIO_WEBM: + return audio_webm() + if self is MediaContentType.VIDEO_MP4: + return video_mp4() + if self is MediaContentType.VIDEO_WEBM: + return video_webm() + if self is MediaContentType.VIDEO_OGG: + return video_ogg() + if self is MediaContentType.VIDEO_MPEG: + return video_mpeg() + if self is MediaContentType.VIDEO_QUICKTIME: + return video_quicktime() + if self is MediaContentType.VIDEO_X_MSVIDEO: + return video_x_msvideo() + if self is MediaContentType.VIDEO_X_MATROSKA: + return video_x_matroska() + if self is MediaContentType.TEXT_PLAIN: + return text_plain() + if self is MediaContentType.TEXT_HTML: + return text_html() + if self is MediaContentType.TEXT_CSS: + return text_css() + if self is MediaContentType.TEXT_CSV: + return text_csv() + if self is MediaContentType.TEXT_MARKDOWN: + return text_markdown() + if self is MediaContentType.TEXT_X_PYTHON: + return text_x_python() + if self is MediaContentType.APPLICATION_JAVASCRIPT: + return application_javascript() + if self is MediaContentType.TEXT_X_TYPESCRIPT: + return text_x_typescript() + if self is MediaContentType.APPLICATION_X_YAML: + return application_x_yaml() + if self is MediaContentType.APPLICATION_PDF: + return application_pdf() + if self is MediaContentType.APPLICATION_MSWORD: + return application_msword() + if self is MediaContentType.APPLICATION_MS_EXCEL: + return application_ms_excel() + if self is MediaContentType.APPLICATION_OPENXML_SPREADSHEET: + return application_openxml_spreadsheet() + if self is MediaContentType.APPLICATION_ZIP: + return application_zip() + if self is MediaContentType.APPLICATION_JSON: + return application_json() + if self is MediaContentType.APPLICATION_XML: + return application_xml() + if self is MediaContentType.APPLICATION_OCTET_STREAM: + return application_octet_stream() + if self is MediaContentType.APPLICATION_OPENXML_WORD: + return application_openxml_word() + if self is MediaContentType.APPLICATION_OPENXML_PRESENTATION: + return application_openxml_presentation() + if self is MediaContentType.APPLICATION_RTF: + return application_rtf() + if self is MediaContentType.APPLICATION_X_NDJSON: + return application_x_ndjson() + if self is MediaContentType.APPLICATION_PARQUET: + return application_parquet() + if self is MediaContentType.APPLICATION_GZIP: + return application_gzip() + if self is MediaContentType.APPLICATION_X_TAR: + return application_x_tar() + if self is MediaContentType.APPLICATION_X7Z_COMPRESSED: + return application_x7z_compressed() diff --git a/langfuse/api/organizations/client.py b/langfuse/api/organizations/client.py index e49d8106d..085c14c5f 100644 --- a/langfuse/api/organizations/client.py +++ b/langfuse/api/organizations/client.py @@ -91,6 +91,7 @@ def update_organization_membership( Examples -------- from langfuse import LangfuseAPI + from langfuse.organizations import MembershipRole client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -102,7 +103,7 @@ def update_organization_membership( ) client.organizations.update_organization_membership( user_id="userId", - role="OWNER", + role=MembershipRole.OWNER, ) """ _response = self._raw_client.update_organization_membership( @@ -218,6 +219,7 @@ def update_project_membership( Examples -------- from langfuse import LangfuseAPI + from langfuse.organizations import MembershipRole client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -230,7 +232,7 @@ def update_project_membership( client.organizations.update_project_membership( project_id="projectId", user_id="userId", - role="OWNER", + role=MembershipRole.OWNER, ) """ _response = self._raw_client.update_project_membership( @@ -437,6 +439,7 @@ async def update_organization_membership( import asyncio from langfuse import AsyncLangfuseAPI + from langfuse.organizations import MembershipRole client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -451,7 +454,7 @@ async def update_organization_membership( async def main() -> None: await client.organizations.update_organization_membership( user_id="userId", - role="OWNER", + role=MembershipRole.OWNER, ) @@ -588,6 +591,7 @@ async def update_project_membership( import asyncio from langfuse import AsyncLangfuseAPI + from langfuse.organizations import MembershipRole client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -603,7 +607,7 @@ async def main() -> None: await client.organizations.update_project_membership( project_id="projectId", user_id="userId", - role="OWNER", + role=MembershipRole.OWNER, ) diff --git a/langfuse/api/organizations/types/membership_role.py b/langfuse/api/organizations/types/membership_role.py index d7683b8d5..fa84eec3a 100644 --- a/langfuse/api/organizations/types/membership_role.py +++ b/langfuse/api/organizations/types/membership_role.py @@ -2,6 +2,29 @@ import typing -MembershipRole = typing.Union[ - typing.Literal["OWNER", "ADMIN", "MEMBER", "VIEWER"], typing.Any -] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class MembershipRole(enum.StrEnum): + OWNER = "OWNER" + ADMIN = "ADMIN" + MEMBER = "MEMBER" + VIEWER = "VIEWER" + + def visit( + self, + owner: typing.Callable[[], T_Result], + admin: typing.Callable[[], T_Result], + member: typing.Callable[[], T_Result], + viewer: typing.Callable[[], T_Result], + ) -> T_Result: + if self is MembershipRole.OWNER: + return owner() + if self is MembershipRole.ADMIN: + return admin() + if self is MembershipRole.MEMBER: + return member() + if self is MembershipRole.VIEWER: + return viewer() diff --git a/langfuse/api/prompts/client.py b/langfuse/api/prompts/client.py index cb1fd9917..fc6203787 100644 --- a/langfuse/api/prompts/client.py +++ b/langfuse/api/prompts/client.py @@ -171,7 +171,11 @@ def create( Examples -------- from langfuse import LangfuseAPI - from langfuse.prompts import ChatMessage, CreateChatPromptRequest + from langfuse.prompts import ( + ChatMessage, + CreateChatPromptRequest, + CreateChatPromptType, + ) client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -194,7 +198,7 @@ def create( content="content", ), ], - type="chat", + type=CreateChatPromptType.CHAT, ), ) """ @@ -429,7 +433,11 @@ async def create( import asyncio from langfuse import AsyncLangfuseAPI - from langfuse.prompts import ChatMessage, CreateChatPromptRequest + from langfuse.prompts import ( + ChatMessage, + CreateChatPromptRequest, + CreateChatPromptType, + ) client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -455,7 +463,7 @@ async def main() -> None: content="content", ), ], - type="chat", + type=CreateChatPromptType.CHAT, ), ) diff --git a/langfuse/api/prompts/types/create_chat_prompt_type.py b/langfuse/api/prompts/types/create_chat_prompt_type.py index 66bb234f8..12f6748a4 100644 --- a/langfuse/api/prompts/types/create_chat_prompt_type.py +++ b/langfuse/api/prompts/types/create_chat_prompt_type.py @@ -2,4 +2,14 @@ import typing -CreateChatPromptType = typing.Union[typing.Literal["chat"], typing.Any] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class CreateChatPromptType(enum.StrEnum): + CHAT = "chat" + + def visit(self, chat: typing.Callable[[], T_Result]) -> T_Result: + if self is CreateChatPromptType.CHAT: + return chat() diff --git a/langfuse/api/prompts/types/create_text_prompt_type.py b/langfuse/api/prompts/types/create_text_prompt_type.py index 9229bd220..825fcee0d 100644 --- a/langfuse/api/prompts/types/create_text_prompt_type.py +++ b/langfuse/api/prompts/types/create_text_prompt_type.py @@ -2,4 +2,14 @@ import typing -CreateTextPromptType = typing.Union[typing.Literal["text"], typing.Any] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class CreateTextPromptType(enum.StrEnum): + TEXT = "text" + + def visit(self, text: typing.Callable[[], T_Result]) -> T_Result: + if self is CreateTextPromptType.TEXT: + return text() diff --git a/langfuse/api/prompts/types/prompt_type.py b/langfuse/api/prompts/types/prompt_type.py index a6676ae50..7d8230db2 100644 --- a/langfuse/api/prompts/types/prompt_type.py +++ b/langfuse/api/prompts/types/prompt_type.py @@ -2,4 +2,19 @@ import typing -PromptType = typing.Union[typing.Literal["chat", "text"], typing.Any] +from ...core import enum + +T_Result = typing.TypeVar("T_Result") + + +class PromptType(enum.StrEnum): + CHAT = "chat" + TEXT = "text" + + def visit( + self, chat: typing.Callable[[], T_Result], text: typing.Callable[[], T_Result] + ) -> T_Result: + if self is PromptType.CHAT: + return chat() + if self is PromptType.TEXT: + return text() diff --git a/langfuse/api/score_configs/client.py b/langfuse/api/score_configs/client.py index 1b5f93bb0..97df2b05a 100644 --- a/langfuse/api/score_configs/client.py +++ b/langfuse/api/score_configs/client.py @@ -71,6 +71,7 @@ def create( Examples -------- from langfuse import LangfuseAPI + from langfuse.commons import ScoreDataType client = LangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -82,7 +83,7 @@ def create( ) client.score_configs.create( name="name", - data_type="NUMERIC", + data_type=ScoreDataType.NUMERIC, ) """ _response = self._raw_client.create( @@ -312,6 +313,7 @@ async def create( import asyncio from langfuse import AsyncLangfuseAPI + from langfuse.commons import ScoreDataType client = AsyncLangfuseAPI( x_langfuse_sdk_name="YOUR_X_LANGFUSE_SDK_NAME", @@ -326,7 +328,7 @@ async def create( async def main() -> None: await client.score_configs.create( name="name", - data_type="NUMERIC", + data_type=ScoreDataType.NUMERIC, ) From 96a8050f077bfcdd7769dcb68c78674a21501f5d Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 22 Dec 2025 14:49:06 +0100 Subject: [PATCH 11/15] push --- tests/test_datasets.py | 5 ++--- tests/test_propagate_attributes.py | 9 +++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/test_datasets.py b/tests/test_datasets.py index 3b18a5a66..af19fd470 100644 --- a/tests/test_datasets.py +++ b/tests/test_datasets.py @@ -7,8 +7,7 @@ from langchain_openai import OpenAI from langfuse import Langfuse, observe -from langfuse.api import DatasetStatus -from langfuse.api import Observation +from langfuse.api import DatasetStatus, Observation from langfuse.langchain import CallbackHandler from tests.utils import create_uuid, get_api @@ -220,7 +219,7 @@ def test_get_dataset_runs(): langfuse.flush() time.sleep(1) # Give API time to process - runs = langfuse.api + runs = langfuse.api.datasets.get_runs(dataset_name=dataset_name) assert len(runs.data) == 2 assert runs.data[0].name == run_name_2 diff --git a/tests/test_propagate_attributes.py b/tests/test_propagate_attributes.py index c4a2799e2..739d2b641 100644 --- a/tests/test_propagate_attributes.py +++ b/tests/test_propagate_attributes.py @@ -7,6 +7,7 @@ import concurrent.futures import time +from datetime import datetime import pytest from opentelemetry.instrumentation.threading import ThreadingInstrumentor @@ -14,6 +15,8 @@ from langfuse import propagate_attributes from langfuse._client.attributes import LangfuseOtelSpanAttributes, _serialize from langfuse._client.constants import LANGFUSE_SDK_EXPERIMENT_ENVIRONMENT +from langfuse._client.datasets import DatasetClient, DatasetItemClient +from langfuse.api import Dataset, DatasetItem, DatasetStatus from tests.test_otel import TestOTelBase @@ -2437,12 +2440,6 @@ def test_experiment_attributes_propagate_with_dataset( self, langfuse_client, memory_exporter, monkeypatch ): """Test experiment attribute propagation with Langfuse dataset.""" - import time - from datetime import datetime - - from langfuse._client.attributes import _serialize - from langfuse._client.datasets import DatasetClient, DatasetItemClient - from langfuse.model import Dataset, DatasetItem, DatasetStatus # Mock the async API to create dataset run items async def mock_create_dataset_run_item(*args, **kwargs): From 49811f908ca57a41dfa96c1e293ef77b7af4046e Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 22 Dec 2025 14:53:55 +0100 Subject: [PATCH 12/15] push --- langfuse/api/.fern/metadata.json | 3 +- .../types/annotation_queue.py | 15 +- .../annotation_queue_assignment_request.py | 15 +- .../types/annotation_queue_item.py | 15 +- ...te_annotation_queue_assignment_response.py | 15 +- .../create_annotation_queue_item_request.py | 15 +- .../types/create_annotation_queue_request.py | 15 +- ...te_annotation_queue_assignment_response.py | 15 +- .../delete_annotation_queue_item_response.py | 15 +- .../types/paginated_annotation_queue_items.py | 15 +- .../types/paginated_annotation_queues.py | 15 +- .../update_annotation_queue_item_request.py | 15 +- ...b_storage_integration_deletion_response.py | 15 +- .../blob_storage_integration_response.py | 15 +- .../blob_storage_integrations_response.py | 15 +- ...create_blob_storage_integration_request.py | 15 +- .../comments/types/create_comment_request.py | 15 +- .../comments/types/create_comment_response.py | 15 +- .../comments/types/get_comments_response.py | 15 +- langfuse/api/commons/types/base_score.py | 15 +- langfuse/api/commons/types/base_score_v1.py | 15 +- langfuse/api/commons/types/boolean_score.py | 14 +- .../api/commons/types/boolean_score_v1.py | 14 +- .../api/commons/types/categorical_score.py | 14 +- .../api/commons/types/categorical_score_v1.py | 14 +- langfuse/api/commons/types/comment.py | 15 +- langfuse/api/commons/types/config_category.py | 15 +- langfuse/api/commons/types/dataset.py | 15 +- langfuse/api/commons/types/dataset_item.py | 15 +- langfuse/api/commons/types/dataset_run.py | 15 +- .../api/commons/types/dataset_run_item.py | 15 +- .../commons/types/dataset_run_with_items.py | 14 +- langfuse/api/commons/types/model.py | 15 +- langfuse/api/commons/types/model_price.py | 15 +- langfuse/api/commons/types/numeric_score.py | 14 +- .../api/commons/types/numeric_score_v1.py | 14 +- langfuse/api/commons/types/observation.py | 15 +- .../api/commons/types/observations_view.py | 14 +- langfuse/api/commons/types/pricing_tier.py | 15 +- .../commons/types/pricing_tier_condition.py | 15 +- .../api/commons/types/pricing_tier_input.py | 15 +- langfuse/api/commons/types/score.py | 41 ++---- langfuse/api/commons/types/score_config.py | 15 +- langfuse/api/commons/types/score_v1.py | 41 ++---- langfuse/api/commons/types/session.py | 15 +- .../api/commons/types/session_with_traces.py | 14 +- langfuse/api/commons/types/trace.py | 15 +- .../api/commons/types/trace_with_details.py | 14 +- .../commons/types/trace_with_full_details.py | 14 +- langfuse/api/commons/types/usage.py | 15 +- .../types/create_dataset_item_request.py | 15 +- .../types/delete_dataset_item_response.py | 15 +- .../types/paginated_dataset_items.py | 15 +- .../types/create_dataset_run_item_request.py | 15 +- .../types/paginated_dataset_run_items.py | 15 +- .../datasets/types/create_dataset_request.py | 15 +- .../types/delete_dataset_run_response.py | 15 +- .../datasets/types/paginated_dataset_runs.py | 15 +- .../api/datasets/types/paginated_datasets.py | 15 +- langfuse/api/health/types/health_response.py | 15 +- langfuse/api/ingestion/types/base_event.py | 15 +- .../api/ingestion/types/create_event_body.py | 14 +- .../api/ingestion/types/create_event_event.py | 14 +- .../ingestion/types/create_generation_body.py | 14 +- .../types/create_generation_event.py | 14 +- .../types/create_observation_event.py | 14 +- .../api/ingestion/types/create_span_body.py | 14 +- .../api/ingestion/types/create_span_event.py | 14 +- .../api/ingestion/types/ingestion_error.py | 15 +- .../api/ingestion/types/ingestion_event.py | 132 ++++-------------- .../api/ingestion/types/ingestion_response.py | 15 +- .../api/ingestion/types/ingestion_success.py | 15 +- .../api/ingestion/types/observation_body.py | 15 +- .../types/open_ai_completion_usage_schema.py | 15 +- .../types/open_ai_response_usage_schema.py | 15 +- langfuse/api/ingestion/types/open_ai_usage.py | 15 +- .../types/optional_observation_body.py | 15 +- langfuse/api/ingestion/types/score_body.py | 15 +- langfuse/api/ingestion/types/score_event.py | 14 +- langfuse/api/ingestion/types/sdk_log_body.py | 15 +- langfuse/api/ingestion/types/sdk_log_event.py | 14 +- langfuse/api/ingestion/types/trace_body.py | 15 +- langfuse/api/ingestion/types/trace_event.py | 14 +- .../api/ingestion/types/update_event_body.py | 14 +- .../ingestion/types/update_generation_body.py | 14 +- .../types/update_generation_event.py | 14 +- .../types/update_observation_event.py | 14 +- .../api/ingestion/types/update_span_body.py | 14 +- .../api/ingestion/types/update_span_event.py | 14 +- .../llm_connections/types/llm_connection.py | 15 +- .../types/paginated_llm_connections.py | 15 +- .../types/upsert_llm_connection_request.py | 15 +- .../api/media/types/get_media_response.py | 15 +- .../types/get_media_upload_url_request.py | 15 +- .../types/get_media_upload_url_response.py | 15 +- langfuse/api/media/types/patch_media_body.py | 15 +- .../api/metrics/types/metrics_response.py | 15 +- .../metrics_v2/types/metrics_v2response.py | 15 +- .../api/models/types/create_model_request.py | 15 +- langfuse/api/models/types/paginated_models.py | 15 +- .../api/observations/types/observations.py | 15 +- .../observations/types/observations_views.py | 15 +- .../types/observations_v2meta.py | 15 +- .../types/observations_v2response.py | 15 +- .../api/opentelemetry/types/otel_attribute.py | 15 +- .../types/otel_attribute_value.py | 15 +- .../api/opentelemetry/types/otel_resource.py | 15 +- .../opentelemetry/types/otel_resource_span.py | 15 +- .../api/opentelemetry/types/otel_scope.py | 15 +- .../opentelemetry/types/otel_scope_span.py | 15 +- langfuse/api/opentelemetry/types/otel_span.py | 15 +- .../types/otel_trace_response.py | 15 +- .../types/delete_membership_request.py | 15 +- .../types/membership_deletion_response.py | 15 +- .../organizations/types/membership_request.py | 15 +- .../types/membership_response.py | 15 +- .../types/memberships_response.py | 15 +- .../types/organization_api_key.py | 15 +- .../types/organization_api_keys_response.py | 15 +- .../types/organization_project.py | 15 +- .../types/organization_projects_response.py | 15 +- .../types/api_key_deletion_response.py | 15 +- langfuse/api/projects/types/api_key_list.py | 15 +- .../api/projects/types/api_key_response.py | 15 +- .../api/projects/types/api_key_summary.py | 15 +- langfuse/api/projects/types/project.py | 15 +- .../types/project_deletion_response.py | 15 +- langfuse/api/projects/types/projects.py | 15 +- langfuse/api/prompts/types/base_prompt.py | 15 +- langfuse/api/prompts/types/chat_message.py | 15 +- langfuse/api/prompts/types/chat_prompt.py | 14 +- .../types/create_chat_prompt_request.py | 15 +- .../types/create_text_prompt_request.py | 15 +- .../api/prompts/types/placeholder_message.py | 15 +- langfuse/api/prompts/types/prompt.py | 28 +--- langfuse/api/prompts/types/prompt_meta.py | 15 +- .../types/prompt_meta_list_response.py | 15 +- langfuse/api/prompts/types/text_prompt.py | 14 +- .../api/scim/types/authentication_scheme.py | 15 +- langfuse/api/scim/types/bulk_config.py | 15 +- langfuse/api/scim/types/empty_response.py | 15 +- langfuse/api/scim/types/filter_config.py | 15 +- langfuse/api/scim/types/resource_meta.py | 15 +- langfuse/api/scim/types/resource_type.py | 15 +- .../api/scim/types/resource_types_response.py | 15 +- langfuse/api/scim/types/schema_extension.py | 15 +- langfuse/api/scim/types/schema_resource.py | 15 +- langfuse/api/scim/types/schemas_response.py | 15 +- langfuse/api/scim/types/scim_email.py | 15 +- .../api/scim/types/scim_feature_support.py | 15 +- langfuse/api/scim/types/scim_name.py | 15 +- langfuse/api/scim/types/scim_user.py | 15 +- .../scim/types/scim_users_list_response.py | 15 +- .../api/scim/types/service_provider_config.py | 15 +- langfuse/api/scim/types/user_meta.py | 15 +- .../api/score/types/create_score_request.py | 15 +- .../api/score/types/create_score_response.py | 15 +- .../types/create_score_config_request.py | 15 +- .../api/score_configs/types/score_configs.py | 15 +- .../types/update_score_config_request.py | 15 +- .../api/score_v2/types/get_scores_response.py | 15 +- .../types/get_scores_response_data.py | 41 ++---- .../types/get_scores_response_data_boolean.py | 14 +- .../get_scores_response_data_categorical.py | 14 +- .../types/get_scores_response_data_numeric.py | 14 +- .../types/get_scores_response_trace_data.py | 15 +- .../api/sessions/types/paginated_sessions.py | 15 +- .../api/trace/types/delete_trace_response.py | 15 +- langfuse/api/trace/types/sort.py | 15 +- langfuse/api/trace/types/traces.py | 15 +- .../utils/pagination/types/meta_response.py | 15 +- 171 files changed, 698 insertions(+), 2031 deletions(-) diff --git a/langfuse/api/.fern/metadata.json b/langfuse/api/.fern/metadata.json index 8bf3385f7..4f1a155c9 100644 --- a/langfuse/api/.fern/metadata.json +++ b/langfuse/api/.fern/metadata.json @@ -4,7 +4,8 @@ "generatorVersion": "4.46.2", "generatorConfig": { "pydantic_config": { - "enum_type": "python_enums" + "enum_type": "python_enums", + "version": "v2" }, "client": { "class_name": "LangfuseAPI" diff --git a/langfuse/api/annotation_queues/types/annotation_queue.py b/langfuse/api/annotation_queues/types/annotation_queue.py index 40048fcba..89cc5d407 100644 --- a/langfuse/api/annotation_queues/types/annotation_queue.py +++ b/langfuse/api/annotation_queues/types/annotation_queue.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -23,13 +23,6 @@ class AnnotationQueue(UniversalBaseModel): dt.datetime, FieldMetadata(alias="updatedAt") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/annotation_queues/types/annotation_queue_assignment_request.py b/langfuse/api/annotation_queues/types/annotation_queue_assignment_request.py index 33da0d3e2..e25e4a327 100644 --- a/langfuse/api/annotation_queues/types/annotation_queue_assignment_request.py +++ b/langfuse/api/annotation_queues/types/annotation_queue_assignment_request.py @@ -4,20 +4,13 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata class AnnotationQueueAssignmentRequest(UniversalBaseModel): user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/annotation_queues/types/annotation_queue_item.py b/langfuse/api/annotation_queues/types/annotation_queue_item.py index 51ee9761a..9c4b622d8 100644 --- a/langfuse/api/annotation_queues/types/annotation_queue_item.py +++ b/langfuse/api/annotation_queues/types/annotation_queue_item.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .annotation_queue_object_type import AnnotationQueueObjectType from .annotation_queue_status import AnnotationQueueStatus @@ -29,13 +29,6 @@ class AnnotationQueueItem(UniversalBaseModel): dt.datetime, FieldMetadata(alias="updatedAt") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/annotation_queues/types/create_annotation_queue_assignment_response.py b/langfuse/api/annotation_queues/types/create_annotation_queue_assignment_response.py index 49b8cb216..8f040d3e4 100644 --- a/langfuse/api/annotation_queues/types/create_annotation_queue_assignment_response.py +++ b/langfuse/api/annotation_queues/types/create_annotation_queue_assignment_response.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -13,13 +13,6 @@ class CreateAnnotationQueueAssignmentResponse(UniversalBaseModel): queue_id: typing_extensions.Annotated[str, FieldMetadata(alias="queueId")] project_id: typing_extensions.Annotated[str, FieldMetadata(alias="projectId")] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/annotation_queues/types/create_annotation_queue_item_request.py b/langfuse/api/annotation_queues/types/create_annotation_queue_item_request.py index 8a029385e..b81287ce5 100644 --- a/langfuse/api/annotation_queues/types/create_annotation_queue_item_request.py +++ b/langfuse/api/annotation_queues/types/create_annotation_queue_item_request.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .annotation_queue_object_type import AnnotationQueueObjectType from .annotation_queue_status import AnnotationQueueStatus @@ -20,13 +20,6 @@ class CreateAnnotationQueueItemRequest(UniversalBaseModel): Defaults to PENDING for new queue items """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/annotation_queues/types/create_annotation_queue_request.py b/langfuse/api/annotation_queues/types/create_annotation_queue_request.py index 72e0ba29f..1415ad1a7 100644 --- a/langfuse/api/annotation_queues/types/create_annotation_queue_request.py +++ b/langfuse/api/annotation_queues/types/create_annotation_queue_request.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -15,13 +15,6 @@ class CreateAnnotationQueueRequest(UniversalBaseModel): typing.List[str], FieldMetadata(alias="scoreConfigIds") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/annotation_queues/types/delete_annotation_queue_assignment_response.py b/langfuse/api/annotation_queues/types/delete_annotation_queue_assignment_response.py index ae87e50a4..547e2847e 100644 --- a/langfuse/api/annotation_queues/types/delete_annotation_queue_assignment_response.py +++ b/langfuse/api/annotation_queues/types/delete_annotation_queue_assignment_response.py @@ -3,19 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class DeleteAnnotationQueueAssignmentResponse(UniversalBaseModel): success: bool - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/annotation_queues/types/delete_annotation_queue_item_response.py b/langfuse/api/annotation_queues/types/delete_annotation_queue_item_response.py index 14b295335..ededb3a49 100644 --- a/langfuse/api/annotation_queues/types/delete_annotation_queue_item_response.py +++ b/langfuse/api/annotation_queues/types/delete_annotation_queue_item_response.py @@ -3,20 +3,13 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class DeleteAnnotationQueueItemResponse(UniversalBaseModel): success: bool message: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/annotation_queues/types/paginated_annotation_queue_items.py b/langfuse/api/annotation_queues/types/paginated_annotation_queue_items.py index ace3188fe..140d2efb9 100644 --- a/langfuse/api/annotation_queues/types/paginated_annotation_queue_items.py +++ b/langfuse/api/annotation_queues/types/paginated_annotation_queue_items.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse from .annotation_queue_item import AnnotationQueueItem @@ -12,13 +12,6 @@ class PaginatedAnnotationQueueItems(UniversalBaseModel): data: typing.List[AnnotationQueueItem] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/annotation_queues/types/paginated_annotation_queues.py b/langfuse/api/annotation_queues/types/paginated_annotation_queues.py index 6e9b36b79..e07a71ac7 100644 --- a/langfuse/api/annotation_queues/types/paginated_annotation_queues.py +++ b/langfuse/api/annotation_queues/types/paginated_annotation_queues.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse from .annotation_queue import AnnotationQueue @@ -12,13 +12,6 @@ class PaginatedAnnotationQueues(UniversalBaseModel): data: typing.List[AnnotationQueue] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/annotation_queues/types/update_annotation_queue_item_request.py b/langfuse/api/annotation_queues/types/update_annotation_queue_item_request.py index eef9846af..8f2c2f898 100644 --- a/langfuse/api/annotation_queues/types/update_annotation_queue_item_request.py +++ b/langfuse/api/annotation_queues/types/update_annotation_queue_item_request.py @@ -3,20 +3,13 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .annotation_queue_status import AnnotationQueueStatus class UpdateAnnotationQueueItemRequest(UniversalBaseModel): status: typing.Optional[AnnotationQueueStatus] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py index aaeac99e2..d0c8655b1 100644 --- a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_deletion_response.py @@ -3,19 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class BlobStorageIntegrationDeletionResponse(UniversalBaseModel): message: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py index 0e5821d32..08529ee67 100644 --- a/langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_integration_response.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .blob_storage_export_frequency import BlobStorageExportFrequency from .blob_storage_export_mode import BlobStorageExportMode @@ -53,13 +53,6 @@ class BlobStorageIntegrationResponse(UniversalBaseModel): dt.datetime, FieldMetadata(alias="updatedAt") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/blob_storage_integrations/types/blob_storage_integrations_response.py b/langfuse/api/blob_storage_integrations/types/blob_storage_integrations_response.py index ffa5760a9..0f3f5cdd7 100644 --- a/langfuse/api/blob_storage_integrations/types/blob_storage_integrations_response.py +++ b/langfuse/api/blob_storage_integrations/types/blob_storage_integrations_response.py @@ -3,20 +3,13 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .blob_storage_integration_response import BlobStorageIntegrationResponse class BlobStorageIntegrationsResponse(UniversalBaseModel): data: typing.List[BlobStorageIntegrationResponse] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py b/langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py index 69b56bda0..3a4d9fa06 100644 --- a/langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py +++ b/langfuse/api/blob_storage_integrations/types/create_blob_storage_integration_request.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .blob_storage_export_frequency import BlobStorageExportFrequency from .blob_storage_export_mode import BlobStorageExportMode @@ -86,13 +86,6 @@ class CreateBlobStorageIntegrationRequest(UniversalBaseModel): Custom start date for exports (required when exportMode is FROM_CUSTOM_DATE) """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/comments/types/create_comment_request.py b/langfuse/api/comments/types/create_comment_request.py index 1d5f717c1..56ef2794d 100644 --- a/langfuse/api/comments/types/create_comment_request.py +++ b/langfuse/api/comments/types/create_comment_request.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -42,13 +42,6 @@ class CreateCommentRequest(UniversalBaseModel): The id of the user who created the comment. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/comments/types/create_comment_response.py b/langfuse/api/comments/types/create_comment_response.py index fd7ed95b1..d080349b0 100644 --- a/langfuse/api/comments/types/create_comment_response.py +++ b/langfuse/api/comments/types/create_comment_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class CreateCommentResponse(UniversalBaseModel): @@ -12,13 +12,6 @@ class CreateCommentResponse(UniversalBaseModel): The id of the created object in Langfuse """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/comments/types/get_comments_response.py b/langfuse/api/comments/types/get_comments_response.py index a919bd893..f275210e8 100644 --- a/langfuse/api/comments/types/get_comments_response.py +++ b/langfuse/api/comments/types/get_comments_response.py @@ -4,7 +4,7 @@ import pydantic from ...commons.types.comment import Comment -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse @@ -12,13 +12,6 @@ class GetCommentsResponse(UniversalBaseModel): data: typing.List[Comment] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/base_score.py b/langfuse/api/commons/types/base_score.py index 28618ea70..8115d768a 100644 --- a/langfuse/api/commons/types/base_score.py +++ b/langfuse/api/commons/types/base_score.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .score_source import ScoreSource @@ -57,13 +57,6 @@ class BaseScore(UniversalBaseModel): The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/base_score_v1.py b/langfuse/api/commons/types/base_score_v1.py index 8cd9470fa..ec805424d 100644 --- a/langfuse/api/commons/types/base_score_v1.py +++ b/langfuse/api/commons/types/base_score_v1.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .score_source import ScoreSource @@ -49,13 +49,6 @@ class BaseScoreV1(UniversalBaseModel): The environment from which this score originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/boolean_score.py b/langfuse/api/commons/types/boolean_score.py index 106e45896..2f65cf338 100644 --- a/langfuse/api/commons/types/boolean_score.py +++ b/langfuse/api/commons/types/boolean_score.py @@ -4,7 +4,6 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .base_score import BaseScore @@ -22,13 +21,6 @@ class BooleanScore(BaseScore): The string representation of the score value. Is inferred from the numeric value and equals "True" or "False" """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/boolean_score_v1.py b/langfuse/api/commons/types/boolean_score_v1.py index e024f6260..cf5425255 100644 --- a/langfuse/api/commons/types/boolean_score_v1.py +++ b/langfuse/api/commons/types/boolean_score_v1.py @@ -4,7 +4,6 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .base_score_v1 import BaseScoreV1 @@ -22,13 +21,6 @@ class BooleanScoreV1(BaseScoreV1): The string representation of the score value. Is inferred from the numeric value and equals "True" or "False" """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/categorical_score.py b/langfuse/api/commons/types/categorical_score.py index d8a2a671d..a12ac58c3 100644 --- a/langfuse/api/commons/types/categorical_score.py +++ b/langfuse/api/commons/types/categorical_score.py @@ -4,7 +4,6 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .base_score import BaseScore @@ -22,13 +21,6 @@ class CategoricalScore(BaseScore): The string representation of the score value. If no config is linked, can be any string. Otherwise, must map to a config category """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/categorical_score_v1.py b/langfuse/api/commons/types/categorical_score_v1.py index e6454cc66..8f98af1a8 100644 --- a/langfuse/api/commons/types/categorical_score_v1.py +++ b/langfuse/api/commons/types/categorical_score_v1.py @@ -4,7 +4,6 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .base_score_v1 import BaseScoreV1 @@ -22,13 +21,6 @@ class CategoricalScoreV1(BaseScoreV1): The string representation of the score value. If no config is linked, can be any string. Otherwise, must map to a config category """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/comment.py b/langfuse/api/commons/types/comment.py index 699efdce0..d1926ba5d 100644 --- a/langfuse/api/commons/types/comment.py +++ b/langfuse/api/commons/types/comment.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .comment_object_type import CommentObjectType @@ -28,13 +28,6 @@ class Comment(UniversalBaseModel): typing.Optional[str], FieldMetadata(alias="authorUserId") ] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/config_category.py b/langfuse/api/commons/types/config_category.py index c888d8e73..4ca546e35 100644 --- a/langfuse/api/commons/types/config_category.py +++ b/langfuse/api/commons/types/config_category.py @@ -3,20 +3,13 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class ConfigCategory(UniversalBaseModel): value: float label: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/dataset.py b/langfuse/api/commons/types/dataset.py index baea2c07f..296b26d7c 100644 --- a/langfuse/api/commons/types/dataset.py +++ b/langfuse/api/commons/types/dataset.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -36,13 +36,6 @@ class Dataset(UniversalBaseModel): dt.datetime, FieldMetadata(alias="updatedAt") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/dataset_item.py b/langfuse/api/commons/types/dataset_item.py index 8cbc28578..d3970eb9a 100644 --- a/langfuse/api/commons/types/dataset_item.py +++ b/langfuse/api/commons/types/dataset_item.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .dataset_status import DatasetStatus @@ -33,13 +33,6 @@ class DatasetItem(UniversalBaseModel): dt.datetime, FieldMetadata(alias="updatedAt") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/dataset_run.py b/langfuse/api/commons/types/dataset_run.py index c5e377632..2cf159ca9 100644 --- a/langfuse/api/commons/types/dataset_run.py +++ b/langfuse/api/commons/types/dataset_run.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -58,13 +58,6 @@ class DatasetRun(UniversalBaseModel): The date and time when the dataset run was last updated """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/dataset_run_item.py b/langfuse/api/commons/types/dataset_run_item.py index 1a736fdc9..0093ffdca 100644 --- a/langfuse/api/commons/types/dataset_run_item.py +++ b/langfuse/api/commons/types/dataset_run_item.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -31,13 +31,6 @@ class DatasetRunItem(UniversalBaseModel): dt.datetime, FieldMetadata(alias="updatedAt") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/dataset_run_with_items.py b/langfuse/api/commons/types/dataset_run_with_items.py index 5297dbb4a..b5995dd30 100644 --- a/langfuse/api/commons/types/dataset_run_with_items.py +++ b/langfuse/api/commons/types/dataset_run_with_items.py @@ -4,7 +4,6 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .dataset_run import DatasetRun from .dataset_run_item import DatasetRunItem @@ -15,13 +14,6 @@ class DatasetRunWithItems(DatasetRun): typing.List[DatasetRunItem], FieldMetadata(alias="datasetRunItems") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/model.py b/langfuse/api/commons/types/model.py index f17ae6a2b..2a722e095 100644 --- a/langfuse/api/commons/types/model.py +++ b/langfuse/api/commons/types/model.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .model_price import ModelPrice from .model_usage_unit import ModelUsageUnit @@ -120,13 +120,6 @@ class Model(UniversalBaseModel): If this array is empty, the model uses legacy flat pricing from the inputPrice/outputPrice/totalPrice fields. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/model_price.py b/langfuse/api/commons/types/model_price.py index 2ec43156d..a2e2288fa 100644 --- a/langfuse/api/commons/types/model_price.py +++ b/langfuse/api/commons/types/model_price.py @@ -3,19 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class ModelPrice(UniversalBaseModel): price: float - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/numeric_score.py b/langfuse/api/commons/types/numeric_score.py index 47bda6593..63ced82ab 100644 --- a/langfuse/api/commons/types/numeric_score.py +++ b/langfuse/api/commons/types/numeric_score.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_score import BaseScore @@ -13,13 +12,6 @@ class NumericScore(BaseScore): The numeric value of the score """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/numeric_score_v1.py b/langfuse/api/commons/types/numeric_score_v1.py index 60f7b45a9..872c89aca 100644 --- a/langfuse/api/commons/types/numeric_score_v1.py +++ b/langfuse/api/commons/types/numeric_score_v1.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_score_v1 import BaseScoreV1 @@ -13,13 +12,6 @@ class NumericScoreV1(BaseScoreV1): The numeric value of the score """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/observation.py b/langfuse/api/commons/types/observation.py index 3500834bd..814e0c7f0 100644 --- a/langfuse/api/commons/types/observation.py +++ b/langfuse/api/commons/types/observation.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .map_value import MapValue from .observation_level import ObservationLevel @@ -139,13 +139,6 @@ class Observation(UniversalBaseModel): The environment from which this observation originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/observations_view.py b/langfuse/api/commons/types/observations_view.py index 6f375c925..fc97c27e7 100644 --- a/langfuse/api/commons/types/observations_view.py +++ b/langfuse/api/commons/types/observations_view.py @@ -4,7 +4,6 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .observation import Observation @@ -85,13 +84,6 @@ class ObservationsView(Observation): The time to the first token in seconds """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/pricing_tier.py b/langfuse/api/commons/types/pricing_tier.py index 3a51f54ee..49b99096b 100644 --- a/langfuse/api/commons/types/pricing_tier.py +++ b/langfuse/api/commons/types/pricing_tier.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .pricing_tier_condition import PricingTierCondition @@ -86,13 +86,6 @@ class PricingTier(UniversalBaseModel): Example: {"input": 0.000003, "output": 0.000015} means $3 per million input tokens and $15 per million output tokens. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/pricing_tier_condition.py b/langfuse/api/commons/types/pricing_tier_condition.py index 54ae6d226..9ebbba0af 100644 --- a/langfuse/api/commons/types/pricing_tier_condition.py +++ b/langfuse/api/commons/types/pricing_tier_condition.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .pricing_tier_operator import PricingTierOperator @@ -63,13 +63,6 @@ class PricingTierCondition(UniversalBaseModel): Whether the regex pattern matching is case-sensitive. Default is false (case-insensitive matching). """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/pricing_tier_input.py b/langfuse/api/commons/types/pricing_tier_input.py index 90d62e4b6..c25d7f716 100644 --- a/langfuse/api/commons/types/pricing_tier_input.py +++ b/langfuse/api/commons/types/pricing_tier_input.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .pricing_tier_condition import PricingTierCondition @@ -71,13 +71,6 @@ class PricingTierInput(UniversalBaseModel): Example: {"input": 0.000003, "output": 0.000015} represents $3 per million input tokens and $15 per million output tokens. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/score.py b/langfuse/api/commons/types/score.py index 056f1cdea..777b6874e 100644 --- a/langfuse/api/commons/types/score.py +++ b/langfuse/api/commons/types/score.py @@ -7,7 +7,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .score_source import ScoreSource @@ -52,16 +52,9 @@ class Score_Numeric(UniversalBaseModel): ] = None environment: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class Score_Categorical(UniversalBaseModel): @@ -105,16 +98,9 @@ class Score_Categorical(UniversalBaseModel): ] = None environment: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class Score_Boolean(UniversalBaseModel): @@ -158,16 +144,9 @@ class Score_Boolean(UniversalBaseModel): ] = None environment: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) Score = typing_extensions.Annotated[ diff --git a/langfuse/api/commons/types/score_config.py b/langfuse/api/commons/types/score_config.py index 4f52b3679..2cd30b585 100644 --- a/langfuse/api/commons/types/score_config.py +++ b/langfuse/api/commons/types/score_config.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .config_category import ConfigCategory from .score_data_type import ScoreDataType @@ -58,13 +58,6 @@ class ScoreConfig(UniversalBaseModel): description: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/score_v1.py b/langfuse/api/commons/types/score_v1.py index 47a5ec580..85b843b35 100644 --- a/langfuse/api/commons/types/score_v1.py +++ b/langfuse/api/commons/types/score_v1.py @@ -7,7 +7,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .score_source import ScoreSource @@ -44,16 +44,9 @@ class ScoreV1_Numeric(UniversalBaseModel): ] = None environment: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class ScoreV1_Categorical(UniversalBaseModel): @@ -89,16 +82,9 @@ class ScoreV1_Categorical(UniversalBaseModel): ] = None environment: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class ScoreV1_Boolean(UniversalBaseModel): @@ -134,16 +120,9 @@ class ScoreV1_Boolean(UniversalBaseModel): ] = None environment: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) ScoreV1 = typing_extensions.Annotated[ diff --git a/langfuse/api/commons/types/session.py b/langfuse/api/commons/types/session.py index 6d4aa1d23..ccb21a9ad 100644 --- a/langfuse/api/commons/types/session.py +++ b/langfuse/api/commons/types/session.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -20,13 +20,6 @@ class Session(UniversalBaseModel): The environment from which this session originated. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/session_with_traces.py b/langfuse/api/commons/types/session_with_traces.py index ff33602b8..d04eef54e 100644 --- a/langfuse/api/commons/types/session_with_traces.py +++ b/langfuse/api/commons/types/session_with_traces.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .session import Session from .trace import Trace @@ -11,13 +10,6 @@ class SessionWithTraces(Session): traces: typing.List[Trace] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/trace.py b/langfuse/api/commons/types/trace.py index 4d02e8eb2..fb4555d49 100644 --- a/langfuse/api/commons/types/trace.py +++ b/langfuse/api/commons/types/trace.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -79,13 +79,6 @@ class Trace(UniversalBaseModel): The environment from which this trace originated. Can be any lowercase alphanumeric string with hyphens and underscores that does not start with 'langfuse'. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/trace_with_details.py b/langfuse/api/commons/types/trace_with_details.py index 658dbeff4..df4e12da5 100644 --- a/langfuse/api/commons/types/trace_with_details.py +++ b/langfuse/api/commons/types/trace_with_details.py @@ -4,7 +4,6 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .trace import Trace @@ -39,13 +38,6 @@ class TraceWithDetails(Trace): List of score ids """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/trace_with_full_details.py b/langfuse/api/commons/types/trace_with_full_details.py index 00dda3982..288ce8624 100644 --- a/langfuse/api/commons/types/trace_with_full_details.py +++ b/langfuse/api/commons/types/trace_with_full_details.py @@ -4,7 +4,6 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .observations_view import ObservationsView from .score_v1 import ScoreV1 @@ -41,13 +40,6 @@ class TraceWithFullDetails(Trace): List of scores """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/commons/types/usage.py b/langfuse/api/commons/types/usage.py index 2e1970661..bce8057c2 100644 --- a/langfuse/api/commons/types/usage.py +++ b/langfuse/api/commons/types/usage.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .model_usage_unit import ModelUsageUnit @@ -51,13 +51,6 @@ class Usage(UniversalBaseModel): USD total cost, defaults to input+output """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/dataset_items/types/create_dataset_item_request.py b/langfuse/api/dataset_items/types/create_dataset_item_request.py index 43496034e..b778e42ae 100644 --- a/langfuse/api/dataset_items/types/create_dataset_item_request.py +++ b/langfuse/api/dataset_items/types/create_dataset_item_request.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions from ...commons.types.dataset_status import DatasetStatus -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -32,13 +32,6 @@ class CreateDatasetItemRequest(UniversalBaseModel): Defaults to ACTIVE for newly created items """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/dataset_items/types/delete_dataset_item_response.py b/langfuse/api/dataset_items/types/delete_dataset_item_response.py index 5d392540b..982e4f2dd 100644 --- a/langfuse/api/dataset_items/types/delete_dataset_item_response.py +++ b/langfuse/api/dataset_items/types/delete_dataset_item_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class DeleteDatasetItemResponse(UniversalBaseModel): @@ -12,13 +12,6 @@ class DeleteDatasetItemResponse(UniversalBaseModel): Success message after deletion """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/dataset_items/types/paginated_dataset_items.py b/langfuse/api/dataset_items/types/paginated_dataset_items.py index 547796a4d..63a683787 100644 --- a/langfuse/api/dataset_items/types/paginated_dataset_items.py +++ b/langfuse/api/dataset_items/types/paginated_dataset_items.py @@ -4,7 +4,7 @@ import pydantic from ...commons.types.dataset_item import DatasetItem -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse @@ -12,13 +12,6 @@ class PaginatedDatasetItems(UniversalBaseModel): data: typing.List[DatasetItem] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/dataset_run_items/types/create_dataset_run_item_request.py b/langfuse/api/dataset_run_items/types/create_dataset_run_item_request.py index 3cd63ec70..cfa3bc1de 100644 --- a/langfuse/api/dataset_run_items/types/create_dataset_run_item_request.py +++ b/langfuse/api/dataset_run_items/types/create_dataset_run_item_request.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -35,13 +35,6 @@ class CreateDatasetRunItemRequest(UniversalBaseModel): traceId should always be provided. For compatibility with older SDK versions it can also be inferred from the provided observationId. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/dataset_run_items/types/paginated_dataset_run_items.py b/langfuse/api/dataset_run_items/types/paginated_dataset_run_items.py index 0a7e61f43..24f7c1996 100644 --- a/langfuse/api/dataset_run_items/types/paginated_dataset_run_items.py +++ b/langfuse/api/dataset_run_items/types/paginated_dataset_run_items.py @@ -4,7 +4,7 @@ import pydantic from ...commons.types.dataset_run_item import DatasetRunItem -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse @@ -12,13 +12,6 @@ class PaginatedDatasetRunItems(UniversalBaseModel): data: typing.List[DatasetRunItem] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/datasets/types/create_dataset_request.py b/langfuse/api/datasets/types/create_dataset_request.py index d27b4aaa6..9d9b01089 100644 --- a/langfuse/api/datasets/types/create_dataset_request.py +++ b/langfuse/api/datasets/types/create_dataset_request.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -26,13 +26,6 @@ class CreateDatasetRequest(UniversalBaseModel): JSON Schema for validating dataset item expected outputs. When set, all new and existing dataset items will be validated against this schema. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/datasets/types/delete_dataset_run_response.py b/langfuse/api/datasets/types/delete_dataset_run_response.py index cf1dbfc71..024433ef6 100644 --- a/langfuse/api/datasets/types/delete_dataset_run_response.py +++ b/langfuse/api/datasets/types/delete_dataset_run_response.py @@ -3,19 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class DeleteDatasetRunResponse(UniversalBaseModel): message: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/datasets/types/paginated_dataset_runs.py b/langfuse/api/datasets/types/paginated_dataset_runs.py index 154c75248..85cd54c55 100644 --- a/langfuse/api/datasets/types/paginated_dataset_runs.py +++ b/langfuse/api/datasets/types/paginated_dataset_runs.py @@ -4,7 +4,7 @@ import pydantic from ...commons.types.dataset_run import DatasetRun -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse @@ -12,13 +12,6 @@ class PaginatedDatasetRuns(UniversalBaseModel): data: typing.List[DatasetRun] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/datasets/types/paginated_datasets.py b/langfuse/api/datasets/types/paginated_datasets.py index bad6c2ded..a2e83edf1 100644 --- a/langfuse/api/datasets/types/paginated_datasets.py +++ b/langfuse/api/datasets/types/paginated_datasets.py @@ -4,7 +4,7 @@ import pydantic from ...commons.types.dataset import Dataset -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse @@ -12,13 +12,6 @@ class PaginatedDatasets(UniversalBaseModel): data: typing.List[Dataset] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/health/types/health_response.py b/langfuse/api/health/types/health_response.py index b5bd855e5..a1c7a4bea 100644 --- a/langfuse/api/health/types/health_response.py +++ b/langfuse/api/health/types/health_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class HealthResponse(UniversalBaseModel): @@ -25,13 +25,6 @@ class HealthResponse(UniversalBaseModel): status: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/base_event.py b/langfuse/api/ingestion/types/base_event.py index 5d94b2f3d..70c6bcfa4 100644 --- a/langfuse/api/ingestion/types/base_event.py +++ b/langfuse/api/ingestion/types/base_event.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class BaseEvent(UniversalBaseModel): @@ -22,13 +22,6 @@ class BaseEvent(UniversalBaseModel): Optional. Metadata field used by the Langfuse SDKs for debugging. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/create_event_body.py b/langfuse/api/ingestion/types/create_event_body.py index 7de12e469..0473d8a0d 100644 --- a/langfuse/api/ingestion/types/create_event_body.py +++ b/langfuse/api/ingestion/types/create_event_body.py @@ -3,20 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .optional_observation_body import OptionalObservationBody class CreateEventBody(OptionalObservationBody): id: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/create_event_event.py b/langfuse/api/ingestion/types/create_event_event.py index 28212576c..e0cc820e1 100644 --- a/langfuse/api/ingestion/types/create_event_event.py +++ b/langfuse/api/ingestion/types/create_event_event.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_event import BaseEvent from .create_event_body import CreateEventBody @@ -11,13 +10,6 @@ class CreateEventEvent(BaseEvent): body: CreateEventBody - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/create_generation_body.py b/langfuse/api/ingestion/types/create_generation_body.py index 288fe7031..72cb57116 100644 --- a/langfuse/api/ingestion/types/create_generation_body.py +++ b/langfuse/api/ingestion/types/create_generation_body.py @@ -6,7 +6,6 @@ import pydantic import typing_extensions from ...commons.types.map_value import MapValue -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .create_span_body import CreateSpanBody from .ingestion_usage import IngestionUsage @@ -36,13 +35,6 @@ class CreateGenerationBody(CreateSpanBody): typing.Optional[int], FieldMetadata(alias="promptVersion") ] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/create_generation_event.py b/langfuse/api/ingestion/types/create_generation_event.py index 9ce73cda5..d62d6cc41 100644 --- a/langfuse/api/ingestion/types/create_generation_event.py +++ b/langfuse/api/ingestion/types/create_generation_event.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_event import BaseEvent from .create_generation_body import CreateGenerationBody @@ -11,13 +10,6 @@ class CreateGenerationEvent(BaseEvent): body: CreateGenerationBody - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/create_observation_event.py b/langfuse/api/ingestion/types/create_observation_event.py index 7215907b3..06d927f36 100644 --- a/langfuse/api/ingestion/types/create_observation_event.py +++ b/langfuse/api/ingestion/types/create_observation_event.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_event import BaseEvent from .observation_body import ObservationBody @@ -11,13 +10,6 @@ class CreateObservationEvent(BaseEvent): body: ObservationBody - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/create_span_body.py b/langfuse/api/ingestion/types/create_span_body.py index 2481da634..7a47d9748 100644 --- a/langfuse/api/ingestion/types/create_span_body.py +++ b/langfuse/api/ingestion/types/create_span_body.py @@ -5,7 +5,6 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .create_event_body import CreateEventBody @@ -15,13 +14,6 @@ class CreateSpanBody(CreateEventBody): typing.Optional[dt.datetime], FieldMetadata(alias="endTime") ] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/create_span_event.py b/langfuse/api/ingestion/types/create_span_event.py index dbd361f86..6e60cf1fe 100644 --- a/langfuse/api/ingestion/types/create_span_event.py +++ b/langfuse/api/ingestion/types/create_span_event.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_event import BaseEvent from .create_span_body import CreateSpanBody @@ -11,13 +10,6 @@ class CreateSpanEvent(BaseEvent): body: CreateSpanBody - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/ingestion_error.py b/langfuse/api/ingestion/types/ingestion_error.py index 519cb368f..2391d95eb 100644 --- a/langfuse/api/ingestion/types/ingestion_error.py +++ b/langfuse/api/ingestion/types/ingestion_error.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class IngestionError(UniversalBaseModel): @@ -12,13 +12,6 @@ class IngestionError(UniversalBaseModel): message: typing.Optional[str] = None error: typing.Optional[typing.Any] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/ingestion_event.py b/langfuse/api/ingestion/types/ingestion_event.py index 1cf2c5dc2..03202e635 100644 --- a/langfuse/api/ingestion/types/ingestion_event.py +++ b/langfuse/api/ingestion/types/ingestion_event.py @@ -6,7 +6,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .create_event_body import CreateEventBody from .create_generation_body import CreateGenerationBody from .create_span_body import CreateSpanBody @@ -25,16 +25,9 @@ class IngestionEvent_TraceCreate(UniversalBaseModel): timestamp: str metadata: typing.Optional[typing.Any] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class IngestionEvent_ScoreCreate(UniversalBaseModel): @@ -44,16 +37,9 @@ class IngestionEvent_ScoreCreate(UniversalBaseModel): timestamp: str metadata: typing.Optional[typing.Any] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class IngestionEvent_SpanCreate(UniversalBaseModel): @@ -63,16 +49,9 @@ class IngestionEvent_SpanCreate(UniversalBaseModel): timestamp: str metadata: typing.Optional[typing.Any] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class IngestionEvent_SpanUpdate(UniversalBaseModel): @@ -82,16 +61,9 @@ class IngestionEvent_SpanUpdate(UniversalBaseModel): timestamp: str metadata: typing.Optional[typing.Any] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class IngestionEvent_GenerationCreate(UniversalBaseModel): @@ -101,16 +73,9 @@ class IngestionEvent_GenerationCreate(UniversalBaseModel): timestamp: str metadata: typing.Optional[typing.Any] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class IngestionEvent_GenerationUpdate(UniversalBaseModel): @@ -120,16 +85,9 @@ class IngestionEvent_GenerationUpdate(UniversalBaseModel): timestamp: str metadata: typing.Optional[typing.Any] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class IngestionEvent_EventCreate(UniversalBaseModel): @@ -139,16 +97,9 @@ class IngestionEvent_EventCreate(UniversalBaseModel): timestamp: str metadata: typing.Optional[typing.Any] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class IngestionEvent_SdkLog(UniversalBaseModel): @@ -158,16 +109,9 @@ class IngestionEvent_SdkLog(UniversalBaseModel): timestamp: str metadata: typing.Optional[typing.Any] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class IngestionEvent_ObservationCreate(UniversalBaseModel): @@ -177,16 +121,9 @@ class IngestionEvent_ObservationCreate(UniversalBaseModel): timestamp: str metadata: typing.Optional[typing.Any] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class IngestionEvent_ObservationUpdate(UniversalBaseModel): @@ -196,16 +133,9 @@ class IngestionEvent_ObservationUpdate(UniversalBaseModel): timestamp: str metadata: typing.Optional[typing.Any] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) IngestionEvent = typing_extensions.Annotated[ diff --git a/langfuse/api/ingestion/types/ingestion_response.py b/langfuse/api/ingestion/types/ingestion_response.py index dfad21d75..b9781fab5 100644 --- a/langfuse/api/ingestion/types/ingestion_response.py +++ b/langfuse/api/ingestion/types/ingestion_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .ingestion_error import IngestionError from .ingestion_success import IngestionSuccess @@ -12,13 +12,6 @@ class IngestionResponse(UniversalBaseModel): successes: typing.List[IngestionSuccess] errors: typing.List[IngestionError] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/ingestion_success.py b/langfuse/api/ingestion/types/ingestion_success.py index 5afed80c9..e7894797a 100644 --- a/langfuse/api/ingestion/types/ingestion_success.py +++ b/langfuse/api/ingestion/types/ingestion_success.py @@ -3,20 +3,13 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class IngestionSuccess(UniversalBaseModel): id: str status: int - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/observation_body.py b/langfuse/api/ingestion/types/observation_body.py index 32302863c..e989a768f 100644 --- a/langfuse/api/ingestion/types/observation_body.py +++ b/langfuse/api/ingestion/types/observation_body.py @@ -8,7 +8,7 @@ from ...commons.types.map_value import MapValue from ...commons.types.observation_level import ObservationLevel from ...commons.types.usage import Usage -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .observation_type import ObservationType @@ -48,13 +48,6 @@ class ObservationBody(UniversalBaseModel): ] = None environment: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/open_ai_completion_usage_schema.py b/langfuse/api/ingestion/types/open_ai_completion_usage_schema.py index b051f25c5..292c51e79 100644 --- a/langfuse/api/ingestion/types/open_ai_completion_usage_schema.py +++ b/langfuse/api/ingestion/types/open_ai_completion_usage_schema.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class OpenAiCompletionUsageSchema(UniversalBaseModel): @@ -21,13 +21,6 @@ class OpenAiCompletionUsageSchema(UniversalBaseModel): typing.Dict[str, typing.Optional[int]] ] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/open_ai_response_usage_schema.py b/langfuse/api/ingestion/types/open_ai_response_usage_schema.py index 1728aaae4..93cbc7dba 100644 --- a/langfuse/api/ingestion/types/open_ai_response_usage_schema.py +++ b/langfuse/api/ingestion/types/open_ai_response_usage_schema.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class OpenAiResponseUsageSchema(UniversalBaseModel): @@ -19,13 +19,6 @@ class OpenAiResponseUsageSchema(UniversalBaseModel): None ) - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/open_ai_usage.py b/langfuse/api/ingestion/types/open_ai_usage.py index 254ef2281..7c1ab3160 100644 --- a/langfuse/api/ingestion/types/open_ai_usage.py +++ b/langfuse/api/ingestion/types/open_ai_usage.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -23,13 +23,6 @@ class OpenAiUsage(UniversalBaseModel): typing.Optional[int], FieldMetadata(alias="totalTokens") ] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/optional_observation_body.py b/langfuse/api/ingestion/types/optional_observation_body.py index 9422c0c2d..f2aaf9b6d 100644 --- a/langfuse/api/ingestion/types/optional_observation_body.py +++ b/langfuse/api/ingestion/types/optional_observation_body.py @@ -6,7 +6,7 @@ import pydantic import typing_extensions from ...commons.types.observation_level import ObservationLevel -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -31,13 +31,6 @@ class OptionalObservationBody(UniversalBaseModel): version: typing.Optional[str] = None environment: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/score_body.py b/langfuse/api/ingestion/types/score_body.py index dd52ed301..c1406558f 100644 --- a/langfuse/api/ingestion/types/score_body.py +++ b/langfuse/api/ingestion/types/score_body.py @@ -6,7 +6,7 @@ import typing_extensions from ...commons.types.create_score_value import CreateScoreValue from ...commons.types.score_data_type import ScoreDataType -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -66,13 +66,6 @@ class ScoreBody(UniversalBaseModel): Reference a score config on a score. When set, the score name must equal the config name and scores must comply with the config's range and data type. For categorical scores, the value must map to a config category. Numeric scores might be constrained by the score config's max and min values """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/score_event.py b/langfuse/api/ingestion/types/score_event.py index e7ffe9f6c..d0d470899 100644 --- a/langfuse/api/ingestion/types/score_event.py +++ b/langfuse/api/ingestion/types/score_event.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_event import BaseEvent from .score_body import ScoreBody @@ -11,13 +10,6 @@ class ScoreEvent(BaseEvent): body: ScoreBody - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/sdk_log_body.py b/langfuse/api/ingestion/types/sdk_log_body.py index 46fe0ca0f..d5b46f118 100644 --- a/langfuse/api/ingestion/types/sdk_log_body.py +++ b/langfuse/api/ingestion/types/sdk_log_body.py @@ -3,19 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class SdkLogBody(UniversalBaseModel): log: typing.Any - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/sdk_log_event.py b/langfuse/api/ingestion/types/sdk_log_event.py index 0a3e15105..ca303af55 100644 --- a/langfuse/api/ingestion/types/sdk_log_event.py +++ b/langfuse/api/ingestion/types/sdk_log_event.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_event import BaseEvent from .sdk_log_body import SdkLogBody @@ -11,13 +10,6 @@ class SdkLogEvent(BaseEvent): body: SdkLogBody - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/trace_body.py b/langfuse/api/ingestion/types/trace_body.py index 3b108a8b5..7fb2842a0 100644 --- a/langfuse/api/ingestion/types/trace_body.py +++ b/langfuse/api/ingestion/types/trace_body.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -31,13 +31,6 @@ class TraceBody(UniversalBaseModel): Make trace publicly accessible via url """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/trace_event.py b/langfuse/api/ingestion/types/trace_event.py index 89adfa241..54127597a 100644 --- a/langfuse/api/ingestion/types/trace_event.py +++ b/langfuse/api/ingestion/types/trace_event.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_event import BaseEvent from .trace_body import TraceBody @@ -11,13 +10,6 @@ class TraceEvent(BaseEvent): body: TraceBody - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/update_event_body.py b/langfuse/api/ingestion/types/update_event_body.py index 0973d8517..055f66f08 100644 --- a/langfuse/api/ingestion/types/update_event_body.py +++ b/langfuse/api/ingestion/types/update_event_body.py @@ -3,20 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .optional_observation_body import OptionalObservationBody class UpdateEventBody(OptionalObservationBody): id: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/update_generation_body.py b/langfuse/api/ingestion/types/update_generation_body.py index c1a677385..1d453e759 100644 --- a/langfuse/api/ingestion/types/update_generation_body.py +++ b/langfuse/api/ingestion/types/update_generation_body.py @@ -6,7 +6,6 @@ import pydantic import typing_extensions from ...commons.types.map_value import MapValue -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .ingestion_usage import IngestionUsage from .update_span_body import UpdateSpanBody @@ -36,13 +35,6 @@ class UpdateGenerationBody(UpdateSpanBody): typing.Optional[int], FieldMetadata(alias="promptVersion") ] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/update_generation_event.py b/langfuse/api/ingestion/types/update_generation_event.py index d1978fd13..e2c7fe284 100644 --- a/langfuse/api/ingestion/types/update_generation_event.py +++ b/langfuse/api/ingestion/types/update_generation_event.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_event import BaseEvent from .update_generation_body import UpdateGenerationBody @@ -11,13 +10,6 @@ class UpdateGenerationEvent(BaseEvent): body: UpdateGenerationBody - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/update_observation_event.py b/langfuse/api/ingestion/types/update_observation_event.py index 0e8f349ac..5c33e7591 100644 --- a/langfuse/api/ingestion/types/update_observation_event.py +++ b/langfuse/api/ingestion/types/update_observation_event.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_event import BaseEvent from .observation_body import ObservationBody @@ -11,13 +10,6 @@ class UpdateObservationEvent(BaseEvent): body: ObservationBody - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/update_span_body.py b/langfuse/api/ingestion/types/update_span_body.py index 745460221..f094b7cdb 100644 --- a/langfuse/api/ingestion/types/update_span_body.py +++ b/langfuse/api/ingestion/types/update_span_body.py @@ -5,7 +5,6 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from ...core.serialization import FieldMetadata from .update_event_body import UpdateEventBody @@ -15,13 +14,6 @@ class UpdateSpanBody(UpdateEventBody): typing.Optional[dt.datetime], FieldMetadata(alias="endTime") ] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/ingestion/types/update_span_event.py b/langfuse/api/ingestion/types/update_span_event.py index 63dbc6c53..20214ac9d 100644 --- a/langfuse/api/ingestion/types/update_span_event.py +++ b/langfuse/api/ingestion/types/update_span_event.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_event import BaseEvent from .update_span_body import UpdateSpanBody @@ -11,13 +10,6 @@ class UpdateSpanEvent(BaseEvent): body: UpdateSpanBody - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/llm_connections/types/llm_connection.py b/langfuse/api/llm_connections/types/llm_connection.py index 8f147b33f..f74ff98c2 100644 --- a/langfuse/api/llm_connections/types/llm_connection.py +++ b/langfuse/api/llm_connections/types/llm_connection.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -72,13 +72,6 @@ class LlmConnection(UniversalBaseModel): dt.datetime, FieldMetadata(alias="updatedAt") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/llm_connections/types/paginated_llm_connections.py b/langfuse/api/llm_connections/types/paginated_llm_connections.py index d0db0b14d..5d8ce52af 100644 --- a/langfuse/api/llm_connections/types/paginated_llm_connections.py +++ b/langfuse/api/llm_connections/types/paginated_llm_connections.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse from .llm_connection import LlmConnection @@ -12,13 +12,6 @@ class PaginatedLlmConnections(UniversalBaseModel): data: typing.List[LlmConnection] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/llm_connections/types/upsert_llm_connection_request.py b/langfuse/api/llm_connections/types/upsert_llm_connection_request.py index 1ba5cfa49..712362fa1 100644 --- a/langfuse/api/llm_connections/types/upsert_llm_connection_request.py +++ b/langfuse/api/llm_connections/types/upsert_llm_connection_request.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .llm_adapter import LlmAdapter @@ -64,13 +64,6 @@ class UpsertLlmConnectionRequest(UniversalBaseModel): Adapter-specific configuration. Validation rules: - **Bedrock**: Required. Must be `{"region": ""}` (e.g., `{"region":"us-east-1"}`) - **VertexAI**: Optional. If provided, must be `{"location": ""}` (e.g., `{"location":"us-central1"}`) - **Other adapters**: Not supported. Omit this field or set to null. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/media/types/get_media_response.py b/langfuse/api/media/types/get_media_response.py index 05b2aff9b..fc1f70329 100644 --- a/langfuse/api/media/types/get_media_response.py +++ b/langfuse/api/media/types/get_media_response.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -50,13 +50,6 @@ class GetMediaResponse(UniversalBaseModel): The expiry date and time of the media record download URL """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/media/types/get_media_upload_url_request.py b/langfuse/api/media/types/get_media_upload_url_request.py index 6cf733534..99f055847 100644 --- a/langfuse/api/media/types/get_media_upload_url_request.py +++ b/langfuse/api/media/types/get_media_upload_url_request.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .media_content_type import MediaContentType @@ -46,13 +46,6 @@ class GetMediaUploadUrlRequest(UniversalBaseModel): The trace / observation field the media record is associated with. This can be one of `input`, `output`, `metadata` """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/media/types/get_media_upload_url_response.py b/langfuse/api/media/types/get_media_upload_url_response.py index 5cf03abaa..90c735be3 100644 --- a/langfuse/api/media/types/get_media_upload_url_response.py +++ b/langfuse/api/media/types/get_media_upload_url_response.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -23,13 +23,6 @@ class GetMediaUploadUrlResponse(UniversalBaseModel): The unique langfuse identifier of a media record """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/media/types/patch_media_body.py b/langfuse/api/media/types/patch_media_body.py index 3f9cc2495..e5f93f601 100644 --- a/langfuse/api/media/types/patch_media_body.py +++ b/langfuse/api/media/types/patch_media_body.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -38,13 +38,6 @@ class PatchMediaBody(UniversalBaseModel): The time in milliseconds it took to upload the media record """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/metrics/types/metrics_response.py b/langfuse/api/metrics/types/metrics_response.py index ece54976c..ffbbfaa59 100644 --- a/langfuse/api/metrics/types/metrics_response.py +++ b/langfuse/api/metrics/types/metrics_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class MetricsResponse(UniversalBaseModel): @@ -14,13 +14,6 @@ class MetricsResponse(UniversalBaseModel): Histograms will return an array with [lower, upper, height] tuples. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/metrics_v2/types/metrics_v2response.py b/langfuse/api/metrics_v2/types/metrics_v2response.py index 64d26f392..461eaf178 100644 --- a/langfuse/api/metrics_v2/types/metrics_v2response.py +++ b/langfuse/api/metrics_v2/types/metrics_v2response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class MetricsV2Response(UniversalBaseModel): @@ -14,13 +14,6 @@ class MetricsV2Response(UniversalBaseModel): Histograms will return an array with [lower, upper, height] tuples. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/models/types/create_model_request.py b/langfuse/api/models/types/create_model_request.py index c03436ec5..dc19db944 100644 --- a/langfuse/api/models/types/create_model_request.py +++ b/langfuse/api/models/types/create_model_request.py @@ -7,7 +7,7 @@ import typing_extensions from ...commons.types.model_usage_unit import ModelUsageUnit from ...commons.types.pricing_tier_input import PricingTierInput -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -98,13 +98,6 @@ class CreateModelRequest(UniversalBaseModel): Optional. Configuration for the selected tokenizer. Needs to be JSON. See docs for more details. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/models/types/paginated_models.py b/langfuse/api/models/types/paginated_models.py index f0a441246..b4bd803cf 100644 --- a/langfuse/api/models/types/paginated_models.py +++ b/langfuse/api/models/types/paginated_models.py @@ -4,7 +4,7 @@ import pydantic from ...commons.types.model import Model -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse @@ -12,13 +12,6 @@ class PaginatedModels(UniversalBaseModel): data: typing.List[Model] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/observations/types/observations.py b/langfuse/api/observations/types/observations.py index 190d429fd..61a47cdc5 100644 --- a/langfuse/api/observations/types/observations.py +++ b/langfuse/api/observations/types/observations.py @@ -4,7 +4,7 @@ import pydantic from ...commons.types.observation import Observation -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse @@ -12,13 +12,6 @@ class Observations(UniversalBaseModel): data: typing.List[Observation] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/observations/types/observations_views.py b/langfuse/api/observations/types/observations_views.py index e14eaf1a8..ee682ed39 100644 --- a/langfuse/api/observations/types/observations_views.py +++ b/langfuse/api/observations/types/observations_views.py @@ -4,7 +4,7 @@ import pydantic from ...commons.types.observations_view import ObservationsView -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse @@ -12,13 +12,6 @@ class ObservationsViews(UniversalBaseModel): data: typing.List[ObservationsView] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/observations_v2/types/observations_v2meta.py b/langfuse/api/observations_v2/types/observations_v2meta.py index 6d03b2e4d..8f86a6512 100644 --- a/langfuse/api/observations_v2/types/observations_v2meta.py +++ b/langfuse/api/observations_v2/types/observations_v2meta.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class ObservationsV2Meta(UniversalBaseModel): @@ -16,13 +16,6 @@ class ObservationsV2Meta(UniversalBaseModel): Base64-encoded cursor to use for retrieving the next page. If not present, there are no more results. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/observations_v2/types/observations_v2response.py b/langfuse/api/observations_v2/types/observations_v2response.py index ab0b43bd6..e833e1918 100644 --- a/langfuse/api/observations_v2/types/observations_v2response.py +++ b/langfuse/api/observations_v2/types/observations_v2response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .observations_v2meta import ObservationsV2Meta @@ -22,13 +22,6 @@ class ObservationsV2Response(UniversalBaseModel): meta: ObservationsV2Meta - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/opentelemetry/types/otel_attribute.py b/langfuse/api/opentelemetry/types/otel_attribute.py index 61646c471..479a46551 100644 --- a/langfuse/api/opentelemetry/types/otel_attribute.py +++ b/langfuse/api/opentelemetry/types/otel_attribute.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .otel_attribute_value import OtelAttributeValue @@ -22,13 +22,6 @@ class OtelAttribute(UniversalBaseModel): Attribute value """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/opentelemetry/types/otel_attribute_value.py b/langfuse/api/opentelemetry/types/otel_attribute_value.py index 059ca7661..c381dd28f 100644 --- a/langfuse/api/opentelemetry/types/otel_attribute_value.py +++ b/langfuse/api/opentelemetry/types/otel_attribute_value.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -41,13 +41,6 @@ class OtelAttributeValue(UniversalBaseModel): Boolean value """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/opentelemetry/types/otel_resource.py b/langfuse/api/opentelemetry/types/otel_resource.py index 1f86e6d3e..c8f1bf2b0 100644 --- a/langfuse/api/opentelemetry/types/otel_resource.py +++ b/langfuse/api/opentelemetry/types/otel_resource.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .otel_attribute import OtelAttribute @@ -19,13 +19,6 @@ class OtelResource(UniversalBaseModel): Resource attributes like service.name, service.version, etc. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/opentelemetry/types/otel_resource_span.py b/langfuse/api/opentelemetry/types/otel_resource_span.py index feea26eb7..d26404cd3 100644 --- a/langfuse/api/opentelemetry/types/otel_resource_span.py +++ b/langfuse/api/opentelemetry/types/otel_resource_span.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .otel_resource import OtelResource from .otel_scope_span import OtelScopeSpan @@ -27,13 +27,6 @@ class OtelResourceSpan(UniversalBaseModel): Array of scope spans """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/opentelemetry/types/otel_scope.py b/langfuse/api/opentelemetry/types/otel_scope.py index 7e12a16a3..a705fc2ec 100644 --- a/langfuse/api/opentelemetry/types/otel_scope.py +++ b/langfuse/api/opentelemetry/types/otel_scope.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .otel_attribute import OtelAttribute @@ -29,13 +29,6 @@ class OtelScope(UniversalBaseModel): Additional scope attributes """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/opentelemetry/types/otel_scope_span.py b/langfuse/api/opentelemetry/types/otel_scope_span.py index 57179fa23..9736454b5 100644 --- a/langfuse/api/opentelemetry/types/otel_scope_span.py +++ b/langfuse/api/opentelemetry/types/otel_scope_span.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .otel_scope import OtelScope from .otel_span import OtelSpan @@ -23,13 +23,6 @@ class OtelScopeSpan(UniversalBaseModel): Array of spans """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/opentelemetry/types/otel_span.py b/langfuse/api/opentelemetry/types/otel_span.py index 9d5ab14e0..f6ef51a36 100644 --- a/langfuse/api/opentelemetry/types/otel_span.py +++ b/langfuse/api/opentelemetry/types/otel_span.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .otel_attribute import OtelAttribute @@ -71,13 +71,6 @@ class OtelSpan(UniversalBaseModel): Span status object """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/opentelemetry/types/otel_trace_response.py b/langfuse/api/opentelemetry/types/otel_trace_response.py index 5c21cbe7a..02386b088 100644 --- a/langfuse/api/opentelemetry/types/otel_trace_response.py +++ b/langfuse/api/opentelemetry/types/otel_trace_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class OtelTraceResponse(UniversalBaseModel): @@ -11,13 +11,6 @@ class OtelTraceResponse(UniversalBaseModel): Response from trace export request. Empty object indicates success. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/organizations/types/delete_membership_request.py b/langfuse/api/organizations/types/delete_membership_request.py index 3e4d4d24b..a48c85283 100644 --- a/langfuse/api/organizations/types/delete_membership_request.py +++ b/langfuse/api/organizations/types/delete_membership_request.py @@ -4,20 +4,13 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata class DeleteMembershipRequest(UniversalBaseModel): user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/organizations/types/membership_deletion_response.py b/langfuse/api/organizations/types/membership_deletion_response.py index bff8dbca0..b1c0c3940 100644 --- a/langfuse/api/organizations/types/membership_deletion_response.py +++ b/langfuse/api/organizations/types/membership_deletion_response.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -12,13 +12,6 @@ class MembershipDeletionResponse(UniversalBaseModel): message: str user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/organizations/types/membership_request.py b/langfuse/api/organizations/types/membership_request.py index d4b88b35e..c1edbebdd 100644 --- a/langfuse/api/organizations/types/membership_request.py +++ b/langfuse/api/organizations/types/membership_request.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .membership_role import MembershipRole @@ -13,13 +13,6 @@ class MembershipRequest(UniversalBaseModel): user_id: typing_extensions.Annotated[str, FieldMetadata(alias="userId")] role: MembershipRole - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/organizations/types/membership_response.py b/langfuse/api/organizations/types/membership_response.py index 456b0b53b..24074c370 100644 --- a/langfuse/api/organizations/types/membership_response.py +++ b/langfuse/api/organizations/types/membership_response.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .membership_role import MembershipRole @@ -15,13 +15,6 @@ class MembershipResponse(UniversalBaseModel): email: str name: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/organizations/types/memberships_response.py b/langfuse/api/organizations/types/memberships_response.py index 6238d90da..f45dc9942 100644 --- a/langfuse/api/organizations/types/memberships_response.py +++ b/langfuse/api/organizations/types/memberships_response.py @@ -3,20 +3,13 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .membership_response import MembershipResponse class MembershipsResponse(UniversalBaseModel): memberships: typing.List[MembershipResponse] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/organizations/types/organization_api_key.py b/langfuse/api/organizations/types/organization_api_key.py index 4989e3bd2..572015ab3 100644 --- a/langfuse/api/organizations/types/organization_api_key.py +++ b/langfuse/api/organizations/types/organization_api_key.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -26,13 +26,6 @@ class OrganizationApiKey(UniversalBaseModel): str, FieldMetadata(alias="displaySecretKey") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/organizations/types/organization_api_keys_response.py b/langfuse/api/organizations/types/organization_api_keys_response.py index ccca5129e..f0ca789da 100644 --- a/langfuse/api/organizations/types/organization_api_keys_response.py +++ b/langfuse/api/organizations/types/organization_api_keys_response.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .organization_api_key import OrganizationApiKey @@ -14,13 +14,6 @@ class OrganizationApiKeysResponse(UniversalBaseModel): typing.List[OrganizationApiKey], FieldMetadata(alias="apiKeys") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/organizations/types/organization_project.py b/langfuse/api/organizations/types/organization_project.py index f1847c2d1..9df0fe961 100644 --- a/langfuse/api/organizations/types/organization_project.py +++ b/langfuse/api/organizations/types/organization_project.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -20,13 +20,6 @@ class OrganizationProject(UniversalBaseModel): dt.datetime, FieldMetadata(alias="updatedAt") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/organizations/types/organization_projects_response.py b/langfuse/api/organizations/types/organization_projects_response.py index ef10ed030..e70925ae0 100644 --- a/langfuse/api/organizations/types/organization_projects_response.py +++ b/langfuse/api/organizations/types/organization_projects_response.py @@ -3,20 +3,13 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .organization_project import OrganizationProject class OrganizationProjectsResponse(UniversalBaseModel): projects: typing.List[OrganizationProject] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/projects/types/api_key_deletion_response.py b/langfuse/api/projects/types/api_key_deletion_response.py index ffbaf27c8..fd6a69448 100644 --- a/langfuse/api/projects/types/api_key_deletion_response.py +++ b/langfuse/api/projects/types/api_key_deletion_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class ApiKeyDeletionResponse(UniversalBaseModel): @@ -13,13 +13,6 @@ class ApiKeyDeletionResponse(UniversalBaseModel): success: bool - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/projects/types/api_key_list.py b/langfuse/api/projects/types/api_key_list.py index d6bb6b09e..bf38d9be1 100644 --- a/langfuse/api/projects/types/api_key_list.py +++ b/langfuse/api/projects/types/api_key_list.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .api_key_summary import ApiKeySummary @@ -18,13 +18,6 @@ class ApiKeyList(UniversalBaseModel): typing.List[ApiKeySummary], FieldMetadata(alias="apiKeys") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/projects/types/api_key_response.py b/langfuse/api/projects/types/api_key_response.py index 19b751cd7..06ad54610 100644 --- a/langfuse/api/projects/types/api_key_response.py +++ b/langfuse/api/projects/types/api_key_response.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -25,13 +25,6 @@ class ApiKeyResponse(UniversalBaseModel): ] note: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/projects/types/api_key_summary.py b/langfuse/api/projects/types/api_key_summary.py index 4ab1173c3..68d21421b 100644 --- a/langfuse/api/projects/types/api_key_summary.py +++ b/langfuse/api/projects/types/api_key_summary.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -30,13 +30,6 @@ class ApiKeySummary(UniversalBaseModel): str, FieldMetadata(alias="displaySecretKey") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/projects/types/project.py b/langfuse/api/projects/types/project.py index b52b53e58..4f46b7546 100644 --- a/langfuse/api/projects/types/project.py +++ b/langfuse/api/projects/types/project.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -23,13 +23,6 @@ class Project(UniversalBaseModel): Number of days to retain data. Null or 0 means no retention. Omitted if no retention is configured. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/projects/types/project_deletion_response.py b/langfuse/api/projects/types/project_deletion_response.py index bccd5440b..e3d471c78 100644 --- a/langfuse/api/projects/types/project_deletion_response.py +++ b/langfuse/api/projects/types/project_deletion_response.py @@ -3,20 +3,13 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class ProjectDeletionResponse(UniversalBaseModel): success: bool message: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/projects/types/projects.py b/langfuse/api/projects/types/projects.py index 10ce03135..5771c0051 100644 --- a/langfuse/api/projects/types/projects.py +++ b/langfuse/api/projects/types/projects.py @@ -3,20 +3,13 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .project import Project class Projects(UniversalBaseModel): data: typing.List[Project] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/prompts/types/base_prompt.py b/langfuse/api/prompts/types/base_prompt.py index 2924490f2..bd9461600 100644 --- a/langfuse/api/prompts/types/base_prompt.py +++ b/langfuse/api/prompts/types/base_prompt.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -37,13 +37,6 @@ class BasePrompt(UniversalBaseModel): The dependency resolution graph for the current prompt. Null if prompt has no dependencies. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/prompts/types/chat_message.py b/langfuse/api/prompts/types/chat_message.py index 045bf067e..3d29e7140 100644 --- a/langfuse/api/prompts/types/chat_message.py +++ b/langfuse/api/prompts/types/chat_message.py @@ -3,20 +3,13 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class ChatMessage(UniversalBaseModel): role: str content: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/prompts/types/chat_prompt.py b/langfuse/api/prompts/types/chat_prompt.py index 5e40152e9..ce347537f 100644 --- a/langfuse/api/prompts/types/chat_prompt.py +++ b/langfuse/api/prompts/types/chat_prompt.py @@ -3,7 +3,6 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_prompt import BasePrompt from .chat_message_with_placeholders import ChatMessageWithPlaceholders @@ -11,13 +10,6 @@ class ChatPrompt(BasePrompt): prompt: typing.List[ChatMessageWithPlaceholders] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/prompts/types/create_chat_prompt_request.py b/langfuse/api/prompts/types/create_chat_prompt_request.py index 041c3deb2..0fe1de0c1 100644 --- a/langfuse/api/prompts/types/create_chat_prompt_request.py +++ b/langfuse/api/prompts/types/create_chat_prompt_request.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .chat_message_with_placeholders import ChatMessageWithPlaceholders from .create_chat_prompt_type import CreateChatPromptType @@ -32,13 +32,6 @@ class CreateChatPromptRequest(UniversalBaseModel): Commit message for this prompt version. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/prompts/types/create_text_prompt_request.py b/langfuse/api/prompts/types/create_text_prompt_request.py index 94d780ef6..be87a7dde 100644 --- a/langfuse/api/prompts/types/create_text_prompt_request.py +++ b/langfuse/api/prompts/types/create_text_prompt_request.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .create_text_prompt_type import CreateTextPromptType @@ -31,13 +31,6 @@ class CreateTextPromptRequest(UniversalBaseModel): Commit message for this prompt version. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/prompts/types/placeholder_message.py b/langfuse/api/prompts/types/placeholder_message.py index 9764675d0..a75a58bd3 100644 --- a/langfuse/api/prompts/types/placeholder_message.py +++ b/langfuse/api/prompts/types/placeholder_message.py @@ -3,19 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class PlaceholderMessage(UniversalBaseModel): name: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/prompts/types/prompt.py b/langfuse/api/prompts/types/prompt.py index aeea93d3a..813e5992f 100644 --- a/langfuse/api/prompts/types/prompt.py +++ b/langfuse/api/prompts/types/prompt.py @@ -6,7 +6,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .chat_message_with_placeholders import ChatMessageWithPlaceholders @@ -27,16 +27,9 @@ class Prompt_Chat(UniversalBaseModel): FieldMetadata(alias="resolutionGraph"), ] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class Prompt_Text(UniversalBaseModel): @@ -55,16 +48,9 @@ class Prompt_Text(UniversalBaseModel): FieldMetadata(alias="resolutionGraph"), ] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) Prompt = typing_extensions.Annotated[ diff --git a/langfuse/api/prompts/types/prompt_meta.py b/langfuse/api/prompts/types/prompt_meta.py index 75929d448..974a50252 100644 --- a/langfuse/api/prompts/types/prompt_meta.py +++ b/langfuse/api/prompts/types/prompt_meta.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .prompt_type import PromptType @@ -30,13 +30,6 @@ class PromptMeta(UniversalBaseModel): Config object of the most recent prompt version that matches the filters (if any are provided) """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/prompts/types/prompt_meta_list_response.py b/langfuse/api/prompts/types/prompt_meta_list_response.py index 725a86442..22043d008 100644 --- a/langfuse/api/prompts/types/prompt_meta_list_response.py +++ b/langfuse/api/prompts/types/prompt_meta_list_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse from .prompt_meta import PromptMeta @@ -12,13 +12,6 @@ class PromptMetaListResponse(UniversalBaseModel): data: typing.List[PromptMeta] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/prompts/types/text_prompt.py b/langfuse/api/prompts/types/text_prompt.py index 046e904ae..fbc53c2f5 100644 --- a/langfuse/api/prompts/types/text_prompt.py +++ b/langfuse/api/prompts/types/text_prompt.py @@ -3,20 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .base_prompt import BasePrompt class TextPrompt(BasePrompt): prompt: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/authentication_scheme.py b/langfuse/api/scim/types/authentication_scheme.py index 2128971e8..fc1fceb14 100644 --- a/langfuse/api/scim/types/authentication_scheme.py +++ b/langfuse/api/scim/types/authentication_scheme.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -15,13 +15,6 @@ class AuthenticationScheme(UniversalBaseModel): type: str primary: bool - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/bulk_config.py b/langfuse/api/scim/types/bulk_config.py index 099390a33..4a3ae719f 100644 --- a/langfuse/api/scim/types/bulk_config.py +++ b/langfuse/api/scim/types/bulk_config.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -17,13 +17,6 @@ class BulkConfig(UniversalBaseModel): int, FieldMetadata(alias="maxPayloadSize") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/empty_response.py b/langfuse/api/scim/types/empty_response.py index 8b1854e9f..1371104f8 100644 --- a/langfuse/api/scim/types/empty_response.py +++ b/langfuse/api/scim/types/empty_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class EmptyResponse(UniversalBaseModel): @@ -11,13 +11,6 @@ class EmptyResponse(UniversalBaseModel): Empty response for 204 No Content responses """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/filter_config.py b/langfuse/api/scim/types/filter_config.py index 7aab95624..ba9986e56 100644 --- a/langfuse/api/scim/types/filter_config.py +++ b/langfuse/api/scim/types/filter_config.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -12,13 +12,6 @@ class FilterConfig(UniversalBaseModel): supported: bool max_results: typing_extensions.Annotated[int, FieldMetadata(alias="maxResults")] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/resource_meta.py b/langfuse/api/scim/types/resource_meta.py index 3db9e3115..99be2a96e 100644 --- a/langfuse/api/scim/types/resource_meta.py +++ b/langfuse/api/scim/types/resource_meta.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -12,13 +12,6 @@ class ResourceMeta(UniversalBaseModel): resource_type: typing_extensions.Annotated[str, FieldMetadata(alias="resourceType")] location: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/resource_type.py b/langfuse/api/scim/types/resource_type.py index 3dda09de4..9913c465d 100644 --- a/langfuse/api/scim/types/resource_type.py +++ b/langfuse/api/scim/types/resource_type.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .resource_meta import ResourceMeta from .schema_extension import SchemaExtension @@ -22,13 +22,6 @@ class ResourceType(UniversalBaseModel): ] meta: ResourceMeta - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/resource_types_response.py b/langfuse/api/scim/types/resource_types_response.py index 0e5ceae72..8ff1c47d9 100644 --- a/langfuse/api/scim/types/resource_types_response.py +++ b/langfuse/api/scim/types/resource_types_response.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .resource_type import ResourceType @@ -16,13 +16,6 @@ class ResourceTypesResponse(UniversalBaseModel): typing.List[ResourceType], FieldMetadata(alias="Resources") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/schema_extension.py b/langfuse/api/scim/types/schema_extension.py index 4f8d18e85..4a09d6192 100644 --- a/langfuse/api/scim/types/schema_extension.py +++ b/langfuse/api/scim/types/schema_extension.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -12,13 +12,6 @@ class SchemaExtension(UniversalBaseModel): schema_: typing_extensions.Annotated[str, FieldMetadata(alias="schema")] required: bool - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/schema_resource.py b/langfuse/api/scim/types/schema_resource.py index bc667eacb..cafc07dcb 100644 --- a/langfuse/api/scim/types/schema_resource.py +++ b/langfuse/api/scim/types/schema_resource.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from .resource_meta import ResourceMeta @@ -14,13 +14,6 @@ class SchemaResource(UniversalBaseModel): attributes: typing.List[typing.Any] meta: ResourceMeta - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/schemas_response.py b/langfuse/api/scim/types/schemas_response.py index 3dc1ca69f..3162f9431 100644 --- a/langfuse/api/scim/types/schemas_response.py +++ b/langfuse/api/scim/types/schemas_response.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .schema_resource import SchemaResource @@ -16,13 +16,6 @@ class SchemasResponse(UniversalBaseModel): typing.List[SchemaResource], FieldMetadata(alias="Resources") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/scim_email.py b/langfuse/api/scim/types/scim_email.py index b8b0ad893..7d589f0cf 100644 --- a/langfuse/api/scim/types/scim_email.py +++ b/langfuse/api/scim/types/scim_email.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class ScimEmail(UniversalBaseModel): @@ -11,13 +11,6 @@ class ScimEmail(UniversalBaseModel): value: str type: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/scim_feature_support.py b/langfuse/api/scim/types/scim_feature_support.py index af0bb997f..4c24a694d 100644 --- a/langfuse/api/scim/types/scim_feature_support.py +++ b/langfuse/api/scim/types/scim_feature_support.py @@ -3,19 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class ScimFeatureSupport(UniversalBaseModel): supported: bool - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/scim_name.py b/langfuse/api/scim/types/scim_name.py index 14e72d050..53d2d79e3 100644 --- a/langfuse/api/scim/types/scim_name.py +++ b/langfuse/api/scim/types/scim_name.py @@ -3,19 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class ScimName(UniversalBaseModel): formatted: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/scim_user.py b/langfuse/api/scim/types/scim_user.py index c65e94f4b..22d6d50fe 100644 --- a/langfuse/api/scim/types/scim_user.py +++ b/langfuse/api/scim/types/scim_user.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .scim_email import ScimEmail from .scim_name import ScimName @@ -19,13 +19,6 @@ class ScimUser(UniversalBaseModel): emails: typing.List[ScimEmail] meta: UserMeta - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/scim_users_list_response.py b/langfuse/api/scim/types/scim_users_list_response.py index 17cf2ad3d..bcfba30bb 100644 --- a/langfuse/api/scim/types/scim_users_list_response.py +++ b/langfuse/api/scim/types/scim_users_list_response.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .scim_user import ScimUser @@ -20,13 +20,6 @@ class ScimUsersListResponse(UniversalBaseModel): typing.List[ScimUser], FieldMetadata(alias="Resources") ] - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/service_provider_config.py b/langfuse/api/scim/types/service_provider_config.py index bb96fbd3b..48add080e 100644 --- a/langfuse/api/scim/types/service_provider_config.py +++ b/langfuse/api/scim/types/service_provider_config.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .authentication_scheme import AuthenticationScheme from .bulk_config import BulkConfig @@ -31,13 +31,6 @@ class ServiceProviderConfig(UniversalBaseModel): ] meta: ResourceMeta - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/scim/types/user_meta.py b/langfuse/api/scim/types/user_meta.py index b56933bbb..033ed4fa1 100644 --- a/langfuse/api/scim/types/user_meta.py +++ b/langfuse/api/scim/types/user_meta.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -15,13 +15,6 @@ class UserMeta(UniversalBaseModel): typing.Optional[str], FieldMetadata(alias="lastModified") ] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/score/types/create_score_request.py b/langfuse/api/score/types/create_score_request.py index 8c24c19a5..5491031ca 100644 --- a/langfuse/api/score/types/create_score_request.py +++ b/langfuse/api/score/types/create_score_request.py @@ -6,7 +6,7 @@ import typing_extensions from ...commons.types.create_score_value import CreateScoreValue from ...commons.types.score_data_type import ScoreDataType -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -70,13 +70,6 @@ class CreateScoreRequest(UniversalBaseModel): Reference a score config on a score. The unique langfuse identifier of a score config. When passing this field, the dataType and stringValue fields are automatically populated. """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/score/types/create_score_response.py b/langfuse/api/score/types/create_score_response.py index b0c6cdbbf..1c20c0f3a 100644 --- a/langfuse/api/score/types/create_score_response.py +++ b/langfuse/api/score/types/create_score_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class CreateScoreResponse(UniversalBaseModel): @@ -12,13 +12,6 @@ class CreateScoreResponse(UniversalBaseModel): The id of the created object in Langfuse """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/score_configs/types/create_score_config_request.py b/langfuse/api/score_configs/types/create_score_config_request.py index 87b13a054..acd2d1dc3 100644 --- a/langfuse/api/score_configs/types/create_score_config_request.py +++ b/langfuse/api/score_configs/types/create_score_config_request.py @@ -6,7 +6,7 @@ import typing_extensions from ...commons.types.config_category import ConfigCategory from ...commons.types.score_data_type import ScoreDataType -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -41,13 +41,6 @@ class CreateScoreConfigRequest(UniversalBaseModel): Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/score_configs/types/score_configs.py b/langfuse/api/score_configs/types/score_configs.py index 9fe613571..d19763e9f 100644 --- a/langfuse/api/score_configs/types/score_configs.py +++ b/langfuse/api/score_configs/types/score_configs.py @@ -4,7 +4,7 @@ import pydantic from ...commons.types.score_config import ScoreConfig -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse @@ -12,13 +12,6 @@ class ScoreConfigs(UniversalBaseModel): data: typing.List[ScoreConfig] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/score_configs/types/update_score_config_request.py b/langfuse/api/score_configs/types/update_score_config_request.py index 553347baf..5237c544f 100644 --- a/langfuse/api/score_configs/types/update_score_config_request.py +++ b/langfuse/api/score_configs/types/update_score_config_request.py @@ -5,7 +5,7 @@ import pydantic import typing_extensions from ...commons.types.config_category import ConfigCategory -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -48,13 +48,6 @@ class UpdateScoreConfigRequest(UniversalBaseModel): Description is shown across the Langfuse UI and can be used to e.g. explain the config categories in detail, why a numeric range was set, or provide additional context on config name or usage """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/score_v2/types/get_scores_response.py b/langfuse/api/score_v2/types/get_scores_response.py index 87e87e2aa..0ca4d0e40 100644 --- a/langfuse/api/score_v2/types/get_scores_response.py +++ b/langfuse/api/score_v2/types/get_scores_response.py @@ -3,7 +3,7 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse from .get_scores_response_data import GetScoresResponseData @@ -12,13 +12,6 @@ class GetScoresResponse(UniversalBaseModel): data: typing.List[GetScoresResponseData] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/score_v2/types/get_scores_response_data.py b/langfuse/api/score_v2/types/get_scores_response_data.py index 2b15cafd4..ffa3bcb9f 100644 --- a/langfuse/api/score_v2/types/get_scores_response_data.py +++ b/langfuse/api/score_v2/types/get_scores_response_data.py @@ -8,7 +8,7 @@ import pydantic import typing_extensions from ...commons.types.score_source import ScoreSource -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata from .get_scores_response_trace_data import GetScoresResponseTraceData @@ -54,16 +54,9 @@ class GetScoresResponseData_Numeric(UniversalBaseModel): ] = None environment: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class GetScoresResponseData_Categorical(UniversalBaseModel): @@ -108,16 +101,9 @@ class GetScoresResponseData_Categorical(UniversalBaseModel): ] = None environment: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) class GetScoresResponseData_Boolean(UniversalBaseModel): @@ -162,16 +148,9 @@ class GetScoresResponseData_Boolean(UniversalBaseModel): ] = None environment: typing.Optional[str] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) GetScoresResponseData = typing_extensions.Annotated[ diff --git a/langfuse/api/score_v2/types/get_scores_response_data_boolean.py b/langfuse/api/score_v2/types/get_scores_response_data_boolean.py index 0e406bcd6..eee645cd3 100644 --- a/langfuse/api/score_v2/types/get_scores_response_data_boolean.py +++ b/langfuse/api/score_v2/types/get_scores_response_data_boolean.py @@ -4,20 +4,12 @@ import pydantic from ...commons.types.boolean_score import BooleanScore -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .get_scores_response_trace_data import GetScoresResponseTraceData class GetScoresResponseDataBoolean(BooleanScore): trace: typing.Optional[GetScoresResponseTraceData] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/score_v2/types/get_scores_response_data_categorical.py b/langfuse/api/score_v2/types/get_scores_response_data_categorical.py index 27b0ad0ab..edd4e46fa 100644 --- a/langfuse/api/score_v2/types/get_scores_response_data_categorical.py +++ b/langfuse/api/score_v2/types/get_scores_response_data_categorical.py @@ -4,20 +4,12 @@ import pydantic from ...commons.types.categorical_score import CategoricalScore -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .get_scores_response_trace_data import GetScoresResponseTraceData class GetScoresResponseDataCategorical(CategoricalScore): trace: typing.Optional[GetScoresResponseTraceData] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/score_v2/types/get_scores_response_data_numeric.py b/langfuse/api/score_v2/types/get_scores_response_data_numeric.py index 38a686aaa..350be0e0c 100644 --- a/langfuse/api/score_v2/types/get_scores_response_data_numeric.py +++ b/langfuse/api/score_v2/types/get_scores_response_data_numeric.py @@ -4,20 +4,12 @@ import pydantic from ...commons.types.numeric_score import NumericScore -from ...core.pydantic_utilities import IS_PYDANTIC_V2 from .get_scores_response_trace_data import GetScoresResponseTraceData class GetScoresResponseDataNumeric(NumericScore): trace: typing.Optional[GetScoresResponseTraceData] = None - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/score_v2/types/get_scores_response_trace_data.py b/langfuse/api/score_v2/types/get_scores_response_trace_data.py index 15145f6e8..674057172 100644 --- a/langfuse/api/score_v2/types/get_scores_response_trace_data.py +++ b/langfuse/api/score_v2/types/get_scores_response_trace_data.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...core.serialization import FieldMetadata @@ -26,13 +26,6 @@ class GetScoresResponseTraceData(UniversalBaseModel): The environment of the trace referenced by score """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/sessions/types/paginated_sessions.py b/langfuse/api/sessions/types/paginated_sessions.py index 21e97c06d..5d7bd3886 100644 --- a/langfuse/api/sessions/types/paginated_sessions.py +++ b/langfuse/api/sessions/types/paginated_sessions.py @@ -4,7 +4,7 @@ import pydantic from ...commons.types.session import Session -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse @@ -12,13 +12,6 @@ class PaginatedSessions(UniversalBaseModel): data: typing.List[Session] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/trace/types/delete_trace_response.py b/langfuse/api/trace/types/delete_trace_response.py index b505fd68d..173075a83 100644 --- a/langfuse/api/trace/types/delete_trace_response.py +++ b/langfuse/api/trace/types/delete_trace_response.py @@ -3,19 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class DeleteTraceResponse(UniversalBaseModel): message: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/trace/types/sort.py b/langfuse/api/trace/types/sort.py index 0949f598d..b6b992870 100644 --- a/langfuse/api/trace/types/sort.py +++ b/langfuse/api/trace/types/sort.py @@ -3,19 +3,12 @@ import typing import pydantic -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel class Sort(UniversalBaseModel): id: str - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/trace/types/traces.py b/langfuse/api/trace/types/traces.py index 2f0e02f43..b559118e1 100644 --- a/langfuse/api/trace/types/traces.py +++ b/langfuse/api/trace/types/traces.py @@ -4,7 +4,7 @@ import pydantic from ...commons.types.trace_with_details import TraceWithDetails -from ...core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ...core.pydantic_utilities import UniversalBaseModel from ...utils.pagination.types.meta_response import MetaResponse @@ -12,13 +12,6 @@ class Traces(UniversalBaseModel): data: typing.List[TraceWithDetails] meta: MetaResponse - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) diff --git a/langfuse/api/utils/pagination/types/meta_response.py b/langfuse/api/utils/pagination/types/meta_response.py index 7b9169efd..54d3847be 100644 --- a/langfuse/api/utils/pagination/types/meta_response.py +++ b/langfuse/api/utils/pagination/types/meta_response.py @@ -4,7 +4,7 @@ import pydantic import typing_extensions -from ....core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel +from ....core.pydantic_utilities import UniversalBaseModel from ....core.serialization import FieldMetadata @@ -33,13 +33,6 @@ class MetaResponse(UniversalBaseModel): number of total pages given the current limit """ - if IS_PYDANTIC_V2: - model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( - extra="allow", frozen=True - ) # type: ignore # Pydantic v2 - else: - - class Config: - frozen = True - smart_union = True - extra = pydantic.Extra.allow + model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( + extra="allow", frozen=True + ) From a551d3d345477bca0d28112cba132f0352e2fa21 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 22 Dec 2025 15:13:44 +0100 Subject: [PATCH 13/15] push --- tests/test_langchain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_langchain.py b/tests/test_langchain.py index 14c25446f..d83a57ff2 100644 --- a/tests/test_langchain.py +++ b/tests/test_langchain.py @@ -14,7 +14,7 @@ from langgraph.checkpoint.memory import MemorySaver from langgraph.graph import END, START, MessagesState, StateGraph from langgraph.prebuilt import ToolNode -from pydantic.v1 import BaseModel, Field +from pydantic import BaseModel, Field from langfuse._client.client import Langfuse from langfuse.langchain import CallbackHandler From db60433a425f9f7161c45929a8d40dff95953ee9 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 22 Dec 2025 15:29:32 +0100 Subject: [PATCH 14/15] push --- langfuse/_client/attributes.py | 2 +- langfuse/_client/span.py | 18 +++++++++++++----- langfuse/types.py | 34 +--------------------------------- 3 files changed, 15 insertions(+), 39 deletions(-) diff --git a/langfuse/_client/attributes.py b/langfuse/_client/attributes.py index 343c70cdb..832b04091 100644 --- a/langfuse/_client/attributes.py +++ b/langfuse/_client/attributes.py @@ -19,8 +19,8 @@ ObservationTypeSpanLike, ) from langfuse._utils.serializer import EventSerializer +from langfuse.api import MapValue, SpanLevel from langfuse.model import PromptClient -from langfuse.types import MapValue, SpanLevel class LangfuseOtelSpanAttributes: diff --git a/langfuse/_client/span.py b/langfuse/_client/span.py index 2f0000e41..f4877d23f 100644 --- a/langfuse/_client/span.py +++ b/langfuse/_client/span.py @@ -51,8 +51,8 @@ ObservationTypeSpanLike, get_observation_types_list, ) +from langfuse.api import MapValue, ScoreDataType, SpanLevel from langfuse.logger import langfuse_logger -from langfuse.types import MapValue, ScoreDataType, SpanLevel # Factory mapping for observation classes # Note: "event" is handled separately due to special instantiation logic @@ -273,7 +273,9 @@ def score( name: str, value: float, score_id: Optional[str] = None, - data_type: Optional[Literal["NUMERIC", "BOOLEAN"]] = None, + data_type: Optional[ + Literal[ScoreDataType.NUMERIC, ScoreDataType.BOOLEAN] + ] = None, comment: Optional[str] = None, config_id: Optional[str] = None, timestamp: Optional[datetime] = None, @@ -286,7 +288,9 @@ def score( name: str, value: str, score_id: Optional[str] = None, - data_type: Optional[Literal["CATEGORICAL"]] = "CATEGORICAL", + data_type: Optional[ + Literal[ScoreDataType.CATEGORICAL] + ] = ScoreDataType.CATEGORICAL, comment: Optional[str] = None, config_id: Optional[str] = None, timestamp: Optional[datetime] = None, @@ -351,7 +355,9 @@ def score_trace( name: str, value: float, score_id: Optional[str] = None, - data_type: Optional[Literal["NUMERIC", "BOOLEAN"]] = None, + data_type: Optional[ + Literal[ScoreDataType.NUMERIC, ScoreDataType.BOOLEAN] + ] = None, comment: Optional[str] = None, config_id: Optional[str] = None, timestamp: Optional[datetime] = None, @@ -364,7 +370,9 @@ def score_trace( name: str, value: str, score_id: Optional[str] = None, - data_type: Optional[Literal["CATEGORICAL"]] = "CATEGORICAL", + data_type: Optional[ + Literal[ScoreDataType.CATEGORICAL] + ] = ScoreDataType.CATEGORICAL, comment: Optional[str] = None, config_id: Optional[str] = None, timestamp: Optional[datetime] = None, diff --git a/langfuse/types.py b/langfuse/types.py index e9f0b1304..067088e40 100644 --- a/langfuse/types.py +++ b/langfuse/types.py @@ -17,13 +17,10 @@ def my_evaluator(*, output: str, **kwargs) -> Evaluation: ``` """ -from datetime import datetime from typing import ( Any, Dict, - List, Literal, - Optional, Protocol, TypedDict, ) @@ -34,40 +31,13 @@ def my_evaluator(*, output: str, **kwargs) -> Evaluation: from typing_extensions import NotRequired -from langfuse.api import MapValue, MediaContentType, UsageDetails -from langfuse.model import PromptClient +from langfuse.api import MediaContentType SpanLevel = Literal["DEBUG", "DEFAULT", "WARNING", "ERROR"] ScoreDataType = Literal["NUMERIC", "CATEGORICAL", "BOOLEAN"] -class TraceMetadata(TypedDict): - name: Optional[str] - user_id: Optional[str] - session_id: Optional[str] - version: Optional[str] - release: Optional[str] - metadata: Optional[Any] - tags: Optional[List[str]] - public: Optional[bool] - - -class ObservationParams(TraceMetadata, TypedDict): - input: Optional[Any] - output: Optional[Any] - level: Optional[SpanLevel] - status_message: Optional[str] - start_time: Optional[datetime] - end_time: Optional[datetime] - completion_start_time: Optional[datetime] - model: Optional[str] - model_parameters: Optional[Dict[str, MapValue]] - usage_details: Optional[UsageDetails] - cost_details: Optional[Dict[str, float]] - prompt: Optional[PromptClient] - - class MaskFunction(Protocol): """A function that masks data. @@ -103,8 +73,6 @@ class TraceContext(TypedDict): __all__ = [ "SpanLevel", "ScoreDataType", - "TraceMetadata", - "ObservationParams", "MaskFunction", "ParsedMediaReference", "TraceContext", From 41335cc447d280104ab68f5a387fca2705672cd4 Mon Sep 17 00:00:00 2001 From: Hassieb Pakzad <68423100+hassiebp@users.noreply.github.com> Date: Mon, 22 Dec 2025 15:35:01 +0100 Subject: [PATCH 15/15] push --- langfuse/_client/attributes.py | 3 ++- langfuse/_client/span.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/langfuse/_client/attributes.py b/langfuse/_client/attributes.py index 832b04091..3d67ba9b6 100644 --- a/langfuse/_client/attributes.py +++ b/langfuse/_client/attributes.py @@ -19,8 +19,9 @@ ObservationTypeSpanLike, ) from langfuse._utils.serializer import EventSerializer -from langfuse.api import MapValue, SpanLevel +from langfuse.api import MapValue from langfuse.model import PromptClient +from langfuse.types import SpanLevel class LangfuseOtelSpanAttributes: diff --git a/langfuse/_client/span.py b/langfuse/_client/span.py index f4877d23f..2fb93331f 100644 --- a/langfuse/_client/span.py +++ b/langfuse/_client/span.py @@ -51,8 +51,9 @@ ObservationTypeSpanLike, get_observation_types_list, ) -from langfuse.api import MapValue, ScoreDataType, SpanLevel +from langfuse.api import MapValue, ScoreDataType from langfuse.logger import langfuse_logger +from langfuse.types import SpanLevel # Factory mapping for observation classes # Note: "event" is handled separately due to special instantiation logic