arize-phoenix 5.10.0__tar.gz → 5.11.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of arize-phoenix might be problematic. Click here for more details.

Files changed (332) hide show
  1. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/PKG-INFO +2 -1
  2. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/pyproject.toml +1 -0
  3. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/config.py +13 -0
  4. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/facilitator.py +3 -2
  5. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/helpers/playground_clients.py +29 -13
  6. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/helpers/playground_spans.py +6 -0
  7. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/mutations/chat_mutations.py +75 -34
  8. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/subscriptions.py +108 -49
  9. arize_phoenix-5.11.0/src/phoenix/server/static/.vite/manifest.json +78 -0
  10. arize_phoenix-5.10.0/src/phoenix/server/static/assets/components-BXIz9ZO8.js → arize_phoenix-5.11.0/src/phoenix/server/static/assets/components-C_HASv83.js +90 -90
  11. arize_phoenix-5.10.0/src/phoenix/server/static/assets/index-DTut7g1y.js → arize_phoenix-5.11.0/src/phoenix/server/static/assets/index-D7UiCRtr.js +2 -2
  12. arize_phoenix-5.10.0/src/phoenix/server/static/assets/pages-B8FpJuXu.js → arize_phoenix-5.11.0/src/phoenix/server/static/assets/pages-DYHcAdjT.js +313 -264
  13. arize_phoenix-5.10.0/src/phoenix/server/static/assets/vendor-BX8_Znqy.js → arize_phoenix-5.11.0/src/phoenix/server/static/assets/vendor-BCxsh5i3.js +150 -150
  14. arize_phoenix-5.10.0/src/phoenix/server/static/assets/vendor-arizeai-CtHir-Ua.js → arize_phoenix-5.11.0/src/phoenix/server/static/assets/vendor-arizeai-C2CDZgMz.js +28 -28
  15. arize_phoenix-5.10.0/src/phoenix/server/static/assets/vendor-codemirror-DLlGiguX.js → arize_phoenix-5.11.0/src/phoenix/server/static/assets/vendor-codemirror-DYbtnCTn.js +1 -1
  16. arize_phoenix-5.10.0/src/phoenix/server/static/assets/vendor-recharts-CJRple0d.js → arize_phoenix-5.11.0/src/phoenix/server/static/assets/vendor-recharts-P6W8G0Mb.js +1 -1
  17. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/span_evaluations.py +4 -3
  18. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/utilities/json.py +7 -1
  19. arize_phoenix-5.11.0/src/phoenix/version.py +1 -0
  20. arize_phoenix-5.10.0/src/phoenix/server/static/.vite/manifest.json +0 -78
  21. arize_phoenix-5.10.0/src/phoenix/version.py +0 -1
  22. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/.gitignore +0 -0
  23. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/IP_NOTICE +0 -0
  24. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/LICENSE +0 -0
  25. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/README.md +0 -0
  26. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/__init__.py +0 -0
  27. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/auth.py +0 -0
  28. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/core/__init__.py +0 -0
  29. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/core/embedding_dimension.py +0 -0
  30. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/core/model.py +0 -0
  31. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/core/model_schema.py +0 -0
  32. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/core/model_schema_adapter.py +0 -0
  33. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/datetime_utils.py +0 -0
  34. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/README.md +0 -0
  35. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/__init__.py +0 -0
  36. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/alembic.ini +0 -0
  37. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/bulk_inserter.py +0 -0
  38. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/engines.py +0 -0
  39. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/enums.py +0 -0
  40. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/helpers.py +0 -0
  41. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/insertion/__init__.py +0 -0
  42. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/insertion/constants.py +0 -0
  43. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/insertion/dataset.py +0 -0
  44. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/insertion/document_annotation.py +0 -0
  45. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/insertion/evaluation.py +0 -0
  46. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/insertion/helpers.py +0 -0
  47. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/insertion/span.py +0 -0
  48. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/insertion/span_annotation.py +0 -0
  49. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/insertion/trace_annotation.py +0 -0
  50. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/insertion/types.py +0 -0
  51. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/migrate.py +0 -0
  52. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/migrations/__init__.py +0 -0
  53. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/migrations/env.py +0 -0
  54. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/migrations/script.py.mako +0 -0
  55. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/migrations/versions/10460e46d750_datasets.py +0 -0
  56. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +0 -0
  57. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py +0 -0
  58. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/migrations/versions/cf03bd6bae1d_init.py +0 -0
  59. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/db/models.py +0 -0
  60. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/exceptions.py +0 -0
  61. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/experiments/__init__.py +0 -0
  62. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/experiments/evaluators/__init__.py +0 -0
  63. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/experiments/evaluators/base.py +0 -0
  64. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/experiments/evaluators/code_evaluators.py +0 -0
  65. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/experiments/evaluators/llm_evaluators.py +0 -0
  66. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/experiments/evaluators/utils.py +0 -0
  67. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/experiments/functions.py +0 -0
  68. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/experiments/tracing.py +0 -0
  69. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/experiments/types.py +0 -0
  70. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/experiments/utils.py +0 -0
  71. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/inferences/__init__.py +0 -0
  72. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/inferences/errors.py +0 -0
  73. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/inferences/fixtures.py +0 -0
  74. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/inferences/inferences.py +0 -0
  75. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/inferences/schema.py +0 -0
  76. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/inferences/validation.py +0 -0
  77. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/logging/__init__.py +0 -0
  78. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/logging/_config.py +0 -0
  79. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/logging/_filter.py +0 -0
  80. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/logging/_formatter.py +0 -0
  81. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/metrics/README.md +0 -0
  82. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/metrics/__init__.py +0 -0
  83. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/metrics/binning.py +0 -0
  84. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/metrics/metrics.py +0 -0
  85. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/metrics/mixins.py +0 -0
  86. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/metrics/retrieval_metrics.py +0 -0
  87. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/metrics/timeseries.py +0 -0
  88. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/metrics/wrappers.py +0 -0
  89. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/pointcloud/__init__.py +0 -0
  90. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/pointcloud/clustering.py +0 -0
  91. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/pointcloud/pointcloud.py +0 -0
  92. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/pointcloud/projectors.py +0 -0
  93. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/pointcloud/umap_parameters.py +0 -0
  94. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/py.typed +0 -0
  95. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/__init__.py +0 -0
  96. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/README.md +0 -0
  97. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/__init__.py +0 -0
  98. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/auth.py +0 -0
  99. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/context.py +0 -0
  100. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/__init__.py +0 -0
  101. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/annotation_summaries.py +0 -0
  102. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/average_experiment_run_latency.py +0 -0
  103. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/cache/__init__.py +0 -0
  104. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/cache/two_tier_cache.py +0 -0
  105. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/dataset_example_revisions.py +0 -0
  106. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/dataset_example_spans.py +0 -0
  107. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/document_evaluation_summaries.py +0 -0
  108. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/document_evaluations.py +0 -0
  109. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/document_retrieval_metrics.py +0 -0
  110. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/experiment_annotation_summaries.py +0 -0
  111. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/experiment_error_rates.py +0 -0
  112. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/experiment_run_annotations.py +0 -0
  113. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/experiment_run_counts.py +0 -0
  114. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/experiment_sequence_number.py +0 -0
  115. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/latency_ms_quantile.py +0 -0
  116. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/min_start_or_max_end_times.py +0 -0
  117. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/project_by_name.py +0 -0
  118. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/record_counts.py +0 -0
  119. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/span_annotations.py +0 -0
  120. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/span_dataset_examples.py +0 -0
  121. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/span_descendants.py +0 -0
  122. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/span_projects.py +0 -0
  123. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/token_counts.py +0 -0
  124. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/trace_row_ids.py +0 -0
  125. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/user_roles.py +0 -0
  126. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/dataloaders/users.py +0 -0
  127. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/exceptions.py +0 -0
  128. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/helpers/__init__.py +0 -0
  129. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/helpers/dataset_helpers.py +0 -0
  130. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/helpers/playground_registry.py +0 -0
  131. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/AddExamplesToDatasetInput.py +0 -0
  132. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/AddSpansToDatasetInput.py +0 -0
  133. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/ChatCompletionInput.py +0 -0
  134. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/ChatCompletionMessageInput.py +0 -0
  135. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/ClearProjectInput.py +0 -0
  136. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/ClusterInput.py +0 -0
  137. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/Coordinates.py +0 -0
  138. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/CreateDatasetInput.py +0 -0
  139. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/CreateSpanAnnotationInput.py +0 -0
  140. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/CreateTraceAnnotationInput.py +0 -0
  141. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/DataQualityMetricInput.py +0 -0
  142. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/DatasetExampleInput.py +0 -0
  143. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/DatasetSort.py +0 -0
  144. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/DatasetVersionSort.py +0 -0
  145. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/DeleteAnnotationsInput.py +0 -0
  146. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +0 -0
  147. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/DeleteDatasetInput.py +0 -0
  148. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/DeleteExperimentsInput.py +0 -0
  149. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/DimensionFilter.py +0 -0
  150. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/DimensionInput.py +0 -0
  151. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/GenerativeModelInput.py +0 -0
  152. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/Granularity.py +0 -0
  153. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/InvocationParameters.py +0 -0
  154. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/PatchAnnotationInput.py +0 -0
  155. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/PatchDatasetExamplesInput.py +0 -0
  156. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/PatchDatasetInput.py +0 -0
  157. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/PerformanceMetricInput.py +0 -0
  158. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/SpanAnnotationSort.py +0 -0
  159. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/SpanSort.py +0 -0
  160. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/TemplateOptions.py +0 -0
  161. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/TimeRange.py +0 -0
  162. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/TraceAnnotationSort.py +0 -0
  163. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/UserRoleInput.py +0 -0
  164. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/input_types/__init__.py +0 -0
  165. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/interceptor.py +0 -0
  166. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/mutations/__init__.py +0 -0
  167. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/mutations/api_key_mutations.py +0 -0
  168. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/mutations/dataset_mutations.py +0 -0
  169. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/mutations/experiment_mutations.py +0 -0
  170. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/mutations/export_events_mutations.py +0 -0
  171. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/mutations/project_mutations.py +0 -0
  172. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/mutations/span_annotations_mutations.py +0 -0
  173. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/mutations/trace_annotations_mutations.py +0 -0
  174. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/mutations/user_mutations.py +0 -0
  175. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/openapi/__init__.py +0 -0
  176. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/openapi/main.py +0 -0
  177. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/openapi/schema.py +0 -0
  178. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/queries.py +0 -0
  179. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/__init__.py +0 -0
  180. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/auth.py +0 -0
  181. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/embeddings.py +0 -0
  182. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/oauth2.py +0 -0
  183. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/utils.py +0 -0
  184. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/v1/__init__.py +0 -0
  185. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/v1/datasets.py +0 -0
  186. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/v1/evaluations.py +0 -0
  187. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/v1/experiment_evaluations.py +0 -0
  188. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/v1/experiment_runs.py +0 -0
  189. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/v1/experiments.py +0 -0
  190. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/v1/pydantic_compat.py +0 -0
  191. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/v1/spans.py +0 -0
  192. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/v1/traces.py +0 -0
  193. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/routers/v1/utils.py +0 -0
  194. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/schema.py +0 -0
  195. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Annotation.py +0 -0
  196. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/AnnotationSummary.py +0 -0
  197. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/AnnotatorKind.py +0 -0
  198. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/ApiKey.py +0 -0
  199. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/AuthMethod.py +0 -0
  200. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/ChatCompletionMessageRole.py +0 -0
  201. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +0 -0
  202. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Cluster.py +0 -0
  203. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/CreateDatasetPayload.py +0 -0
  204. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/DataQualityMetric.py +0 -0
  205. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Dataset.py +0 -0
  206. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/DatasetExample.py +0 -0
  207. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/DatasetExampleRevision.py +0 -0
  208. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/DatasetValues.py +0 -0
  209. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/DatasetVersion.py +0 -0
  210. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Dimension.py +0 -0
  211. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/DimensionDataType.py +0 -0
  212. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/DimensionShape.py +0 -0
  213. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/DimensionType.py +0 -0
  214. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/DimensionWithValue.py +0 -0
  215. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/DocumentEvaluationSummary.py +0 -0
  216. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/DocumentRetrievalMetrics.py +0 -0
  217. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/EmbeddingDimension.py +0 -0
  218. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/EmbeddingMetadata.py +0 -0
  219. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Evaluation.py +0 -0
  220. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/EvaluationSummary.py +0 -0
  221. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Event.py +0 -0
  222. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/EventMetadata.py +0 -0
  223. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/ExampleRevisionInterface.py +0 -0
  224. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Experiment.py +0 -0
  225. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/ExperimentAnnotationSummary.py +0 -0
  226. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/ExperimentComparison.py +0 -0
  227. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/ExperimentRun.py +0 -0
  228. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/ExperimentRunAnnotation.py +0 -0
  229. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/ExportedFile.py +0 -0
  230. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Functionality.py +0 -0
  231. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/GenerativeModel.py +0 -0
  232. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/GenerativeProvider.py +0 -0
  233. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Inferences.py +0 -0
  234. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/InferencesRole.py +0 -0
  235. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/LabelFraction.py +0 -0
  236. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/MimeType.py +0 -0
  237. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Model.py +0 -0
  238. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/NumericRange.py +0 -0
  239. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/PerformanceMetric.py +0 -0
  240. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Project.py +0 -0
  241. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/PromptResponse.py +0 -0
  242. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Retrieval.py +0 -0
  243. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/ScalarDriftMetricEnum.py +0 -0
  244. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Segments.py +0 -0
  245. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/SortDir.py +0 -0
  246. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Span.py +0 -0
  247. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/SpanAnnotation.py +0 -0
  248. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/SystemApiKey.py +0 -0
  249. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/TemplateLanguage.py +0 -0
  250. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/TimeSeries.py +0 -0
  251. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/Trace.py +0 -0
  252. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/TraceAnnotation.py +0 -0
  253. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/UMAPPoints.py +0 -0
  254. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/User.py +0 -0
  255. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/UserApiKey.py +0 -0
  256. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/UserRole.py +0 -0
  257. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/ValidationResult.py +0 -0
  258. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/VectorDriftMetricEnum.py +0 -0
  259. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/__init__.py +0 -0
  260. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/node.py +0 -0
  261. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/types/pagination.py +0 -0
  262. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/api/utils.py +0 -0
  263. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/app.py +0 -0
  264. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/bearer_auth.py +0 -0
  265. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/dml_event.py +0 -0
  266. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/dml_event_handler.py +0 -0
  267. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/email/__init__.py +0 -0
  268. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/email/sender.py +0 -0
  269. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/email/templates/__init__.py +0 -0
  270. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/email/templates/password_reset.html +0 -0
  271. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/email/types.py +0 -0
  272. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/grpc_server.py +0 -0
  273. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/jwt_store.py +0 -0
  274. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/main.py +0 -0
  275. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/oauth2.py +0 -0
  276. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/openapi/__init__.py +0 -0
  277. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/prometheus.py +0 -0
  278. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/rate_limiters.py +0 -0
  279. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/apple-touch-icon-114x114.png +0 -0
  280. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/apple-touch-icon-120x120.png +0 -0
  281. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/apple-touch-icon-144x144.png +0 -0
  282. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/apple-touch-icon-152x152.png +0 -0
  283. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/apple-touch-icon-180x180.png +0 -0
  284. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/apple-touch-icon-72x72.png +0 -0
  285. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/apple-touch-icon-76x76.png +0 -0
  286. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/apple-touch-icon.png +0 -0
  287. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/assets/vendor-DxkFTwjz.css +0 -0
  288. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/assets/vendor-three-DwGkEfCM.js +0 -0
  289. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/favicon.ico +0 -0
  290. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/static/modernizr.js +0 -0
  291. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/telemetry.py +0 -0
  292. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/templates/__init__.py +0 -0
  293. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/templates/index.html +0 -0
  294. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/thread_server.py +0 -0
  295. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/server/types.py +0 -0
  296. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/services.py +0 -0
  297. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/session/__init__.py +0 -0
  298. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/session/client.py +0 -0
  299. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/session/data_extractor.py +0 -0
  300. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/session/evaluation.py +0 -0
  301. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/session/session.py +0 -0
  302. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/settings.py +0 -0
  303. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/__init__.py +0 -0
  304. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/attributes.py +0 -0
  305. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/dsl/README.md +0 -0
  306. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/dsl/__init__.py +0 -0
  307. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/dsl/filter.py +0 -0
  308. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/dsl/helpers.py +0 -0
  309. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/dsl/query.py +0 -0
  310. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/errors.py +0 -0
  311. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/evaluation_conventions.py +0 -0
  312. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/exporter.py +0 -0
  313. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/fixtures.py +0 -0
  314. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/otel.py +0 -0
  315. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/projects.py +0 -0
  316. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/schemas.py +0 -0
  317. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/span_json_decoder.py +0 -0
  318. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/span_json_encoder.py +0 -0
  319. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/trace_dataset.py +0 -0
  320. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/utils.py +0 -0
  321. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/v1/__init__.py +0 -0
  322. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/v1/evaluation_pb2.py +0 -0
  323. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/trace/v1/evaluation_pb2.pyi +0 -0
  324. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/utilities/__init__.py +0 -0
  325. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/utilities/client.py +0 -0
  326. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/utilities/deprecation.py +0 -0
  327. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/utilities/error_handling.py +0 -0
  328. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/utilities/logging.py +0 -0
  329. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/utilities/project.py +0 -0
  330. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/utilities/re.py +0 -0
  331. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/utilities/span_store.py +0 -0
  332. {arize_phoenix-5.10.0 → arize_phoenix-5.11.0}/src/phoenix/utilities/template_formatters.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: arize-phoenix
3
- Version: 5.10.0
3
+ Version: 5.11.0
4
4
  Summary: AI Observability and Evaluation
5
5
  Project-URL: Documentation, https://docs.arize.com/phoenix/
6
6
  Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
@@ -53,6 +53,7 @@ Requires-Dist: wrapt
53
53
  Provides-Extra: container
54
54
  Requires-Dist: anthropic; extra == 'container'
55
55
  Requires-Dist: fast-hdbscan>=0.2.0; extra == 'container'
56
+ Requires-Dist: google-generativeai; extra == 'container'
56
57
  Requires-Dist: numba>=0.60.0; extra == 'container'
57
58
  Requires-Dist: openai>=1.0.0; extra == 'container'
58
59
  Requires-Dist: opentelemetry-exporter-otlp; extra == 'container'
@@ -121,6 +121,7 @@ pg = [
121
121
  ]
122
122
  container = [
123
123
  "anthropic",
124
+ "google-generativeai",
124
125
  "prometheus-client",
125
126
  "openai>=1.0.0",
126
127
  "opentelemetry-sdk",
@@ -97,6 +97,13 @@ ENV_PHOENIX_SERVER_INSTRUMENTATION_OTLP_TRACE_COLLECTOR_GRPC_ENDPOINT = (
97
97
  ENV_PHOENIX_ENABLE_AUTH = "PHOENIX_ENABLE_AUTH"
98
98
  ENV_PHOENIX_DISABLE_RATE_LIMIT = "PHOENIX_DISABLE_RATE_LIMIT"
99
99
  ENV_PHOENIX_SECRET = "PHOENIX_SECRET"
100
+ ENV_PHOENIX_DEFAULT_ADMIN_INITIAL_PASSWORD = "PHOENIX_DEFAULT_ADMIN_INITIAL_PASSWORD"
101
+ """
102
+ The initial password for the default admin account, which defaults to ‘admin’ if not
103
+ explicitly set. Note that changing this value will have no effect if the default admin
104
+ record already exists in the database. In such cases, the default admin password must
105
+ be updated manually in the application.
106
+ """
100
107
  ENV_PHOENIX_API_KEY = "PHOENIX_API_KEY"
101
108
  ENV_PHOENIX_USE_SECURE_COOKIES = "PHOENIX_USE_SECURE_COOKIES"
102
109
  ENV_PHOENIX_ACCESS_TOKEN_EXPIRY_MINUTES = "PHOENIX_ACCESS_TOKEN_EXPIRY_MINUTES"
@@ -274,6 +281,12 @@ def get_env_phoenix_secret() -> Optional[str]:
274
281
  return phoenix_secret
275
282
 
276
283
 
284
+ def get_env_default_admin_initial_password() -> str:
285
+ from phoenix.auth import DEFAULT_ADMIN_PASSWORD
286
+
287
+ return os.environ.get(ENV_PHOENIX_DEFAULT_ADMIN_INITIAL_PASSWORD) or DEFAULT_ADMIN_PASSWORD
288
+
289
+
277
290
  def get_env_phoenix_use_secure_cookies() -> bool:
278
291
  return _bool_val(ENV_PHOENIX_USE_SECURE_COOKIES, False)
279
292
 
@@ -13,13 +13,13 @@ from sqlalchemy.ext.asyncio import AsyncSession
13
13
 
14
14
  from phoenix.auth import (
15
15
  DEFAULT_ADMIN_EMAIL,
16
- DEFAULT_ADMIN_PASSWORD,
17
16
  DEFAULT_ADMIN_USERNAME,
18
17
  DEFAULT_SECRET_LENGTH,
19
18
  DEFAULT_SYSTEM_EMAIL,
20
19
  DEFAULT_SYSTEM_USERNAME,
21
20
  compute_password_hash,
22
21
  )
22
+ from phoenix.config import get_env_default_admin_initial_password
23
23
  from phoenix.db import models
24
24
  from phoenix.db.enums import COLUMN_ENUMS, UserRole
25
25
  from phoenix.server.types import DbSessionFactory
@@ -97,7 +97,8 @@ async def _ensure_user_roles(session: AsyncSession) -> None:
97
97
  admin_role_id := role_ids.get(admin_role)
98
98
  ) is not None:
99
99
  salt = secrets.token_bytes(DEFAULT_SECRET_LENGTH)
100
- compute = partial(compute_password_hash, password=DEFAULT_ADMIN_PASSWORD, salt=salt)
100
+ password = get_env_default_admin_initial_password()
101
+ compute = partial(compute_password_hash, password=password, salt=salt)
101
102
  loop = asyncio.get_running_loop()
102
103
  hash_ = await loop.run_in_executor(None, compute)
103
104
  admin_user = models.User(
@@ -2,6 +2,7 @@ import asyncio
2
2
  import importlib.util
3
3
  import inspect
4
4
  import json
5
+ import os
5
6
  import time
6
7
  from abc import ABC, abstractmethod
7
8
  from collections.abc import AsyncIterator, Callable, Iterator
@@ -25,6 +26,7 @@ from phoenix.evals.models.rate_limiters import (
25
26
  RateLimiter,
26
27
  RateLimitError,
27
28
  )
29
+ from phoenix.server.api.exceptions import BadRequest
28
30
  from phoenix.server.api.helpers.playground_registry import PROVIDER_DEFAULT, register_llm_client
29
31
  from phoenix.server.api.input_types.GenerativeModelInput import GenerativeModelInput
30
32
  from phoenix.server.api.input_types.InvocationParameters import (
@@ -99,9 +101,9 @@ class PlaygroundRateLimiter(RateLimiter, KeyedSingleton):
99
101
  super().__init__(
100
102
  rate_limit_error=rate_limit_error,
101
103
  max_rate_limit_retries=3,
102
- initial_per_second_request_rate=2.0,
103
- maximum_per_second_request_rate=10.0,
104
- enforcement_window_minutes=1,
104
+ initial_per_second_request_rate=1.0,
105
+ maximum_per_second_request_rate=3.0,
106
+ enforcement_window_minutes=0.05,
105
107
  rate_reduction_factor=0.5,
106
108
  rate_increase_factor=0.01,
107
109
  cooldown_seconds=5,
@@ -128,10 +130,11 @@ class PlaygroundRateLimiter(RateLimiter, KeyedSingleton):
128
130
  self._rate_limit_handling.set() # Set the event as a failsafe
129
131
  await self._throttler.async_wait_until_ready()
130
132
  request_start_time = time.time()
131
- if inspect.iscoroutinefunction(fn):
132
- return await fn(*args, **kwargs) # type: ignore
133
+ maybe_coroutine = fn(*args, **kwargs)
134
+ if inspect.iscoroutine(maybe_coroutine):
135
+ return await maybe_coroutine # type: ignore
133
136
  else:
134
- return fn(*args, **kwargs)
137
+ return maybe_coroutine
135
138
  except self._rate_limit_error:
136
139
  async with self._rate_limit_handling_lock:
137
140
  self._rate_limit_handling.clear() # prevent new requests from starting
@@ -258,6 +261,10 @@ class OpenAIStreamingClient(PlaygroundStreamingClient):
258
261
  from openai import AsyncOpenAI
259
262
  from openai import RateLimitError as OpenAIRateLimitError
260
263
 
264
+ # todo: check if custom base url is set before raising error to allow
265
+ # for custom endpoints that don't require an API key
266
+ if not (api_key := api_key or os.environ.get("OPENAI_API_KEY")):
267
+ raise BadRequest("An API key is required for OpenAI models")
261
268
  super().__init__(model=model, api_key=api_key)
262
269
  self._attributes[LLM_PROVIDER] = OpenInferenceLLMProviderValues.OPENAI.value
263
270
  self._attributes[LLM_SYSTEM] = OpenInferenceLLMSystemValues.OPENAI.value
@@ -341,7 +348,7 @@ class OpenAIStreamingClient(PlaygroundStreamingClient):
341
348
  openai_messages = [self.to_openai_chat_completion_param(*message) for message in messages]
342
349
  tool_call_ids: dict[int, str] = {}
343
350
  token_usage: Optional["CompletionUsage"] = None
344
- throttled_create = self.rate_limiter.alimit(self.client.chat.completions.create)
351
+ throttled_create = self.rate_limiter._alimit(self.client.chat.completions.create)
345
352
  async for chunk in await throttled_create(
346
353
  messages=openai_messages,
347
354
  model=self.model_name,
@@ -510,7 +517,7 @@ class OpenAIO1StreamingClient(OpenAIStreamingClient):
510
517
 
511
518
  tool_call_ids: dict[int, str] = {}
512
519
 
513
- throttled_create = self.rate_limiter.alimit(self.client.chat.completions.create)
520
+ throttled_create = self.rate_limiter._alimit(self.client.chat.completions.create)
514
521
  response = await throttled_create(
515
522
  messages=openai_messages,
516
523
  model=self.model_name,
@@ -618,12 +625,14 @@ class AzureOpenAIStreamingClient(OpenAIStreamingClient):
618
625
  super().__init__(model=model, api_key=api_key)
619
626
  self._attributes[LLM_PROVIDER] = OpenInferenceLLMProviderValues.AZURE.value
620
627
  self._attributes[LLM_SYSTEM] = OpenInferenceLLMSystemValues.OPENAI.value
621
- if model.endpoint is None or model.api_version is None:
622
- raise ValueError("endpoint and api_version are required for Azure OpenAI models")
628
+ if not (endpoint := model.endpoint or os.environ.get("AZURE_OPENAI_ENDPOINT")):
629
+ raise BadRequest("An Azure endpoint is required for Azure OpenAI models")
630
+ if not (api_version := model.api_version or os.environ.get("OPENAI_API_VERSION")):
631
+ raise BadRequest("An OpenAI API version is required for Azure OpenAI models")
623
632
  self.client = AsyncAzureOpenAI(
624
633
  api_key=api_key,
625
- azure_endpoint=model.endpoint,
626
- api_version=model.api_version,
634
+ azure_endpoint=endpoint,
635
+ api_version=api_version,
627
636
  )
628
637
 
629
638
 
@@ -648,6 +657,8 @@ class AnthropicStreamingClient(PlaygroundStreamingClient):
648
657
  super().__init__(model=model, api_key=api_key)
649
658
  self._attributes[LLM_PROVIDER] = OpenInferenceLLMProviderValues.ANTHROPIC.value
650
659
  self._attributes[LLM_SYSTEM] = OpenInferenceLLMSystemValues.ANTHROPIC.value
660
+ if not (api_key := api_key or os.environ.get("ANTHROPIC_API_KEY")):
661
+ raise BadRequest("An API key is required for Anthropic models")
651
662
  self.client = anthropic.AsyncAnthropic(api_key=api_key)
652
663
  self.model_name = model.name
653
664
  self.rate_limiter = PlaygroundRateLimiter(model.provider_key, anthropic.RateLimitError)
@@ -707,7 +718,6 @@ class AnthropicStreamingClient(PlaygroundStreamingClient):
707
718
  "messages": anthropic_messages,
708
719
  "model": self.model_name,
709
720
  "system": system_prompt,
710
- "max_tokens": 1024,
711
721
  "tools": tools,
712
722
  **invocation_parameters,
713
723
  }
@@ -820,6 +830,12 @@ class GeminiStreamingClient(PlaygroundStreamingClient):
820
830
  super().__init__(model=model, api_key=api_key)
821
831
  self._attributes[LLM_PROVIDER] = OpenInferenceLLMProviderValues.GOOGLE.value
822
832
  self._attributes[LLM_SYSTEM] = OpenInferenceLLMSystemValues.VERTEXAI.value
833
+ if not (
834
+ api_key := api_key
835
+ or os.environ.get("GEMINI_API_KEY")
836
+ or os.environ.get("GOOGLE_API_KEY")
837
+ ):
838
+ raise BadRequest("An API key is required for Gemini models")
823
839
  google_genai.configure(api_key=api_key)
824
840
  self.model_name = model.name
825
841
 
@@ -379,6 +379,11 @@ def _llm_output_messages(
379
379
  if content := "".join(chunk.content for chunk in text_chunks):
380
380
  yield f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_CONTENT}", content
381
381
  for tool_call_index, (_tool_call_id, tool_call_chunks_) in enumerate(tool_call_chunks.items()):
382
+ if _tool_call_id:
383
+ yield (
384
+ f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_ID}",
385
+ _tool_call_id,
386
+ )
382
387
  if tool_call_chunks_ and (name := tool_call_chunks_[0].function.name):
383
388
  yield (
384
389
  f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_FUNCTION_NAME}",
@@ -441,6 +446,7 @@ MESSAGE_CONTENT = MessageAttributes.MESSAGE_CONTENT
441
446
  MESSAGE_ROLE = MessageAttributes.MESSAGE_ROLE
442
447
  MESSAGE_TOOL_CALLS = MessageAttributes.MESSAGE_TOOL_CALLS
443
448
 
449
+ TOOL_CALL_ID = ToolCallAttributes.TOOL_CALL_ID
444
450
  TOOL_CALL_FUNCTION_NAME = ToolCallAttributes.TOOL_CALL_FUNCTION_NAME
445
451
  TOOL_CALL_FUNCTION_ARGUMENTS_JSON = ToolCallAttributes.TOOL_CALL_FUNCTION_ARGUMENTS_JSON
446
452
  TOOL_CALL_ID = ToolCallAttributes.TOOL_CALL_ID
@@ -1,9 +1,9 @@
1
1
  import asyncio
2
2
  from dataclasses import asdict, field
3
3
  from datetime import datetime, timezone
4
- from itertools import chain
4
+ from itertools import chain, islice
5
5
  from traceback import format_exc
6
- from typing import Any, Iterable, Iterator, List, Optional, Union
6
+ from typing import Any, Iterable, Iterator, List, Optional, TypeVar, Union
7
7
 
8
8
  import strawberry
9
9
  from openinference.instrumentation import safe_json_dumps
@@ -26,7 +26,7 @@ from phoenix.datetime_utils import local_now, normalize_datetime
26
26
  from phoenix.db import models
27
27
  from phoenix.db.helpers import get_dataset_example_revisions
28
28
  from phoenix.server.api.context import Context
29
- from phoenix.server.api.exceptions import BadRequest, NotFound
29
+ from phoenix.server.api.exceptions import BadRequest, CustomGraphQLError, NotFound
30
30
  from phoenix.server.api.helpers.playground_clients import (
31
31
  PlaygroundStreamingClient,
32
32
  initialize_playground_clients,
@@ -127,11 +127,19 @@ class ChatCompletionMutationMixin:
127
127
  provider_key = input.model.provider_key
128
128
  llm_client_class = PLAYGROUND_CLIENT_REGISTRY.get_client(provider_key, input.model.name)
129
129
  if llm_client_class is None:
130
- raise BadRequest(f"No LLM client registered for provider '{provider_key}'")
131
- llm_client = llm_client_class(
132
- model=input.model,
133
- api_key=input.api_key,
134
- )
130
+ raise BadRequest(f"Unknown LLM provider: '{provider_key.value}'")
131
+ try:
132
+ llm_client = llm_client_class(
133
+ model=input.model,
134
+ api_key=input.api_key,
135
+ )
136
+ except CustomGraphQLError:
137
+ raise
138
+ except Exception as error:
139
+ raise BadRequest(
140
+ f"Failed to connect to LLM API for {provider_key.value} {input.model.name}: "
141
+ f"{str(error)}"
142
+ )
135
143
  dataset_id = from_global_id_with_expected_type(input.dataset_id, Dataset.__name__)
136
144
  dataset_version_id = (
137
145
  from_global_id_with_expected_type(
@@ -158,7 +166,9 @@ class ChatCompletionMutationMixin:
158
166
  revisions = [
159
167
  revision
160
168
  async for revision in await session.stream_scalars(
161
- get_dataset_example_revisions(resolved_version_id)
169
+ get_dataset_example_revisions(resolved_version_id).order_by(
170
+ models.DatasetExampleRevision.id
171
+ )
162
172
  )
163
173
  ]
164
174
  if not revisions:
@@ -181,28 +191,32 @@ class ChatCompletionMutationMixin:
181
191
  session.add(experiment)
182
192
  await session.flush()
183
193
 
194
+ results = []
195
+ batch_size = 3
184
196
  start_time = datetime.now(timezone.utc)
185
- results = await asyncio.gather(
186
- *(
187
- cls._chat_completion(
188
- info,
189
- llm_client,
190
- ChatCompletionInput(
191
- model=input.model,
192
- api_key=input.api_key,
193
- messages=input.messages,
194
- tools=input.tools,
195
- invocation_parameters=input.invocation_parameters,
196
- template=TemplateOptions(
197
- language=input.template_language,
198
- variables=revision.input,
197
+ for batch in _get_batches(revisions, batch_size):
198
+ batch_results = await asyncio.gather(
199
+ *(
200
+ cls._chat_completion(
201
+ info,
202
+ llm_client,
203
+ ChatCompletionInput(
204
+ model=input.model,
205
+ api_key=input.api_key,
206
+ messages=input.messages,
207
+ tools=input.tools,
208
+ invocation_parameters=input.invocation_parameters,
209
+ template=TemplateOptions(
210
+ language=input.template_language,
211
+ variables=revision.input,
212
+ ),
199
213
  ),
200
- ),
201
- )
202
- for revision in revisions
203
- ),
204
- return_exceptions=True,
205
- )
214
+ )
215
+ for revision in batch
216
+ ),
217
+ return_exceptions=True,
218
+ )
219
+ results.extend(batch_results)
206
220
 
207
221
  payload = ChatCompletionOverDatasetMutationPayload(
208
222
  dataset_id=GlobalID(models.Dataset.__name__, str(dataset.id)),
@@ -266,11 +280,19 @@ class ChatCompletionMutationMixin:
266
280
  provider_key = input.model.provider_key
267
281
  llm_client_class = PLAYGROUND_CLIENT_REGISTRY.get_client(provider_key, input.model.name)
268
282
  if llm_client_class is None:
269
- raise BadRequest(f"No LLM client registered for provider '{provider_key}'")
270
- llm_client = llm_client_class(
271
- model=input.model,
272
- api_key=input.api_key,
273
- )
283
+ raise BadRequest(f"Unknown LLM provider: '{provider_key.value}'")
284
+ try:
285
+ llm_client = llm_client_class(
286
+ model=input.model,
287
+ api_key=input.api_key,
288
+ )
289
+ except CustomGraphQLError:
290
+ raise
291
+ except Exception as error:
292
+ raise BadRequest(
293
+ f"Failed to connect to LLM API for {provider_key.value} {input.model.name}: "
294
+ f"{str(error)}"
295
+ )
274
296
  return await cls._chat_completion(info, llm_client, input)
275
297
 
276
298
  @classmethod
@@ -486,6 +508,11 @@ def _llm_output_messages(
486
508
  if text_content:
487
509
  yield f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_CONTENT}", text_content
488
510
  for tool_call_index, tool_call in enumerate(tool_calls.values()):
511
+ if tool_call_id := tool_call.id:
512
+ yield (
513
+ f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_ID}",
514
+ tool_call_id,
515
+ )
489
516
  yield (
490
517
  f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_FUNCTION_NAME}",
491
518
  tool_call.function.name,
@@ -513,6 +540,19 @@ def _serialize_event(event: SpanException) -> dict[str, Any]:
513
540
  return {k: (v.isoformat() if isinstance(v, datetime) else v) for k, v in asdict(event).items()}
514
541
 
515
542
 
543
+ _AnyT = TypeVar("_AnyT")
544
+
545
+
546
+ def _get_batches(
547
+ iterable: Iterable[_AnyT],
548
+ batch_size: int,
549
+ ) -> Iterator[list[_AnyT]]:
550
+ """Splits an iterable into batches not exceeding a specified size."""
551
+ iterator = iter(iterable)
552
+ while batch := list(islice(iterator, batch_size)):
553
+ yield batch
554
+
555
+
516
556
  JSON = OpenInferenceMimeTypeValues.JSON.value
517
557
  TEXT = OpenInferenceMimeTypeValues.TEXT.value
518
558
  LLM = OpenInferenceSpanKindValues.LLM.value
@@ -534,6 +574,7 @@ MESSAGE_CONTENT = MessageAttributes.MESSAGE_CONTENT
534
574
  MESSAGE_ROLE = MessageAttributes.MESSAGE_ROLE
535
575
  MESSAGE_TOOL_CALLS = MessageAttributes.MESSAGE_TOOL_CALLS
536
576
 
577
+ TOOL_CALL_ID = ToolCallAttributes.TOOL_CALL_ID
537
578
  TOOL_CALL_FUNCTION_NAME = ToolCallAttributes.TOOL_CALL_FUNCTION_NAME
538
579
  TOOL_CALL_FUNCTION_ARGUMENTS_JSON = ToolCallAttributes.TOOL_CALL_FUNCTION_ARGUMENTS_JSON
539
580
 
@@ -2,9 +2,10 @@ import asyncio
2
2
  import logging
3
3
  from asyncio import FIRST_COMPLETED, Queue, QueueEmpty, Task, create_task, wait, wait_for
4
4
  from collections.abc import AsyncIterator, Iterator
5
- from datetime import datetime, timezone
5
+ from datetime import datetime, timedelta, timezone
6
6
  from typing import (
7
7
  Any,
8
+ AsyncGenerator,
8
9
  Iterable,
9
10
  Mapping,
10
11
  Optional,
@@ -24,7 +25,7 @@ from typing_extensions import TypeAlias, assert_never
24
25
  from phoenix.datetime_utils import local_now, normalize_datetime
25
26
  from phoenix.db import models
26
27
  from phoenix.server.api.context import Context
27
- from phoenix.server.api.exceptions import BadRequest, NotFound
28
+ from phoenix.server.api.exceptions import BadRequest, CustomGraphQLError, NotFound
28
29
  from phoenix.server.api.helpers.playground_clients import (
29
30
  PlaygroundStreamingClient,
30
31
  initialize_playground_clients,
@@ -79,6 +80,7 @@ DatasetExampleID: TypeAlias = GlobalID
79
80
  ChatCompletionResult: TypeAlias = tuple[
80
81
  DatasetExampleID, Optional[models.Span], models.ExperimentRun
81
82
  ]
83
+ ChatStream: TypeAlias = AsyncGenerator[ChatCompletionSubscriptionPayload, None]
82
84
  PLAYGROUND_PROJECT_NAME = "playground"
83
85
 
84
86
 
@@ -91,11 +93,19 @@ class Subscription:
91
93
  provider_key = input.model.provider_key
92
94
  llm_client_class = PLAYGROUND_CLIENT_REGISTRY.get_client(provider_key, input.model.name)
93
95
  if llm_client_class is None:
94
- raise BadRequest(f"No LLM client registered for provider '{provider_key}'")
95
- llm_client = llm_client_class(
96
- model=input.model,
97
- api_key=input.api_key,
98
- )
96
+ raise BadRequest(f"Unknown LLM provider: '{provider_key.value}'")
97
+ try:
98
+ llm_client = llm_client_class(
99
+ model=input.model,
100
+ api_key=input.api_key,
101
+ )
102
+ except CustomGraphQLError:
103
+ raise
104
+ except Exception as error:
105
+ raise BadRequest(
106
+ f"Failed to connect to LLM API for {provider_key.value} {input.model.name}: "
107
+ f"{str(error)}"
108
+ )
99
109
 
100
110
  messages = [
101
111
  (
@@ -158,7 +168,19 @@ class Subscription:
158
168
  provider_key = input.model.provider_key
159
169
  llm_client_class = PLAYGROUND_CLIENT_REGISTRY.get_client(provider_key, input.model.name)
160
170
  if llm_client_class is None:
161
- raise BadRequest(f"No LLM client registered for provider '{provider_key}'")
171
+ raise BadRequest(f"Unknown LLM provider: '{provider_key.value}'")
172
+ try:
173
+ llm_client = llm_client_class(
174
+ model=input.model,
175
+ api_key=input.api_key,
176
+ )
177
+ except CustomGraphQLError:
178
+ raise
179
+ except Exception as error:
180
+ raise BadRequest(
181
+ f"Failed to connect to LLM API for {provider_key.value} {input.model.name}: "
182
+ f"{str(error)}"
183
+ )
162
184
 
163
185
  dataset_id = from_global_id_with_expected_type(input.dataset_id, Dataset.__name__)
164
186
  version_id = (
@@ -264,45 +286,76 @@ class Subscription:
264
286
  experiment=to_gql_experiment(experiment)
265
287
  ) # eagerly yields experiment so it can be linked by consumers of the subscription
266
288
 
267
- results_queue: Queue[ChatCompletionResult] = Queue()
268
- chat_completion_streams = [
269
- _stream_chat_completion_over_dataset_example(
270
- input=input,
271
- llm_client_class=llm_client_class,
272
- revision=revision,
273
- results_queue=results_queue,
274
- experiment_id=experiment.id,
275
- project_id=playground_project_id,
289
+ results: Queue[ChatCompletionResult] = Queue()
290
+ not_started: list[tuple[DatasetExampleID, ChatStream]] = [
291
+ (
292
+ GlobalID(DatasetExample.__name__, str(revision.dataset_example_id)),
293
+ _stream_chat_completion_over_dataset_example(
294
+ input=input,
295
+ llm_client=llm_client,
296
+ revision=revision,
297
+ results=results,
298
+ experiment_id=experiment.id,
299
+ project_id=playground_project_id,
300
+ ),
276
301
  )
277
302
  for revision in revisions
278
303
  ]
279
- stream_to_async_tasks: dict[
280
- AsyncIterator[ChatCompletionSubscriptionPayload],
281
- Task[ChatCompletionSubscriptionPayload],
282
- ] = {iterator: _create_task_with_timeout(iterator) for iterator in chat_completion_streams}
283
- batch_size = 10
284
- while stream_to_async_tasks:
285
- async_tasks_to_run = [task for task in stream_to_async_tasks.values()]
304
+ in_progress: list[
305
+ tuple[Optional[DatasetExampleID], ChatStream, Task[ChatCompletionSubscriptionPayload]]
306
+ ] = []
307
+ max_in_progress = 3
308
+ write_batch_size = 10
309
+ write_interval = timedelta(seconds=10)
310
+ last_write_time = datetime.now()
311
+ while not_started or in_progress:
312
+ while not_started and len(in_progress) < max_in_progress:
313
+ ex_id, stream = not_started.pop()
314
+ task = _create_task_with_timeout(stream)
315
+ in_progress.append((ex_id, stream, task))
316
+ async_tasks_to_run = [task for _, _, task in in_progress]
286
317
  completed_tasks, _ = await wait(async_tasks_to_run, return_when=FIRST_COMPLETED)
287
- for task in completed_tasks:
288
- iterator = next(it for it, t in stream_to_async_tasks.items() if t == task)
318
+ for completed_task in completed_tasks:
319
+ idx = [task for _, _, task in in_progress].index(completed_task)
320
+ example_id, stream, _ = in_progress[idx]
289
321
  try:
290
- yield task.result()
291
- except (StopAsyncIteration, asyncio.TimeoutError):
292
- del stream_to_async_tasks[iterator] # removes exhausted iterator
322
+ yield completed_task.result()
323
+ except StopAsyncIteration:
324
+ del in_progress[idx] # removes exhausted stream
325
+ except asyncio.TimeoutError:
326
+ del in_progress[idx] # removes timed-out stream
327
+ if example_id is not None:
328
+ yield ChatCompletionSubscriptionError(
329
+ message="Timed out", dataset_example_id=example_id
330
+ )
293
331
  except Exception as error:
294
- del stream_to_async_tasks[iterator] # removes failed iterator
332
+ del in_progress[idx] # removes failed stream
333
+ if example_id is not None:
334
+ yield ChatCompletionSubscriptionError(
335
+ message="An unexpected error occurred", dataset_example_id=example_id
336
+ )
295
337
  logger.exception(error)
296
338
  else:
297
- stream_to_async_tasks[iterator] = _create_task_with_timeout(iterator)
298
- if results_queue.qsize() >= batch_size:
299
- result_iterator = _chat_completion_result_payloads(
300
- db=info.context.db, results=_drain_no_wait(results_queue)
301
- )
302
- stream_to_async_tasks[result_iterator] = _create_task_with_timeout(
303
- result_iterator
339
+ task = _create_task_with_timeout(stream)
340
+ in_progress[idx] = (example_id, stream, task)
341
+
342
+ exceeded_write_batch_size = results.qsize() >= write_batch_size
343
+ exceeded_write_interval = datetime.now() - last_write_time > write_interval
344
+ write_already_in_progress = any(
345
+ _is_result_payloads_stream(stream) for _, stream, _ in in_progress
346
+ )
347
+ if (
348
+ not results.empty()
349
+ and (exceeded_write_batch_size or exceeded_write_interval)
350
+ and not write_already_in_progress
351
+ ):
352
+ result_payloads_stream = _chat_completion_result_payloads(
353
+ db=info.context.db, results=_drain_no_wait(results)
304
354
  )
305
- if remaining_results := await _drain(results_queue):
355
+ task = _create_task_with_timeout(result_payloads_stream)
356
+ in_progress.append((None, result_payloads_stream, task))
357
+ last_write_time = datetime.now()
358
+ if remaining_results := await _drain(results):
306
359
  async for result_payload in _chat_completion_result_payloads(
307
360
  db=info.context.db, results=remaining_results
308
361
  ):
@@ -312,17 +365,13 @@ class Subscription:
312
365
  async def _stream_chat_completion_over_dataset_example(
313
366
  *,
314
367
  input: ChatCompletionOverDatasetInput,
315
- llm_client_class: type["PlaygroundStreamingClient"],
368
+ llm_client: PlaygroundStreamingClient,
316
369
  revision: models.DatasetExampleRevision,
317
- results_queue: Queue[ChatCompletionResult],
370
+ results: Queue[ChatCompletionResult],
318
371
  experiment_id: int,
319
372
  project_id: int,
320
- ) -> AsyncIterator[ChatCompletionSubscriptionPayload]:
373
+ ) -> ChatStream:
321
374
  example_id = GlobalID(DatasetExample.__name__, str(revision.dataset_example_id))
322
- llm_client = llm_client_class(
323
- model=input.model,
324
- api_key=input.api_key,
325
- )
326
375
  invocation_parameters = llm_client.construct_invocation_parameters(input.invocation_parameters)
327
376
  messages = [
328
377
  (
@@ -345,7 +394,7 @@ async def _stream_chat_completion_over_dataset_example(
345
394
  except TemplateFormatterError as error:
346
395
  format_end_time = cast(datetime, normalize_datetime(dt=local_now(), tz=timezone.utc))
347
396
  yield ChatCompletionSubscriptionError(message=str(error), dataset_example_id=example_id)
348
- await results_queue.put(
397
+ await results.put(
349
398
  (
350
399
  example_id,
351
400
  None,
@@ -380,7 +429,7 @@ async def _stream_chat_completion_over_dataset_example(
380
429
  db_run = get_db_experiment_run(
381
430
  db_span, db_trace, experiment_id=experiment_id, example_id=revision.dataset_example_id
382
431
  )
383
- await results_queue.put((example_id, db_span, db_run))
432
+ await results.put((example_id, db_span, db_run))
384
433
  if span.status_message is not None:
385
434
  yield ChatCompletionSubscriptionError(
386
435
  message=span.status_message, dataset_example_id=example_id
@@ -391,7 +440,7 @@ async def _chat_completion_result_payloads(
391
440
  *,
392
441
  db: DbSessionFactory,
393
442
  results: Sequence[ChatCompletionResult],
394
- ) -> AsyncIterator[ChatCompletionSubscriptionResult]:
443
+ ) -> ChatStream:
395
444
  if not results:
396
445
  return
397
446
  async with db() as session:
@@ -408,8 +457,18 @@ async def _chat_completion_result_payloads(
408
457
  )
409
458
 
410
459
 
460
+ def _is_result_payloads_stream(
461
+ stream: ChatStream,
462
+ ) -> bool:
463
+ """
464
+ Checks if the given generator was instantiated from
465
+ `_chat_completion_result_payloads`
466
+ """
467
+ return stream.ag_code == _chat_completion_result_payloads.__code__
468
+
469
+
411
470
  def _create_task_with_timeout(
412
- iterable: AsyncIterator[GenericType], timeout_in_seconds: int = 60
471
+ iterable: AsyncIterator[GenericType], timeout_in_seconds: int = 90
413
472
  ) -> Task[GenericType]:
414
473
  return create_task(wait_for(_as_coroutine(iterable), timeout=timeout_in_seconds))
415
474