arize-phoenix 10.0.4__py3-none-any.whl → 12.28.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. {arize_phoenix-10.0.4.dist-info → arize_phoenix-12.28.1.dist-info}/METADATA +124 -72
  2. arize_phoenix-12.28.1.dist-info/RECORD +499 -0
  3. {arize_phoenix-10.0.4.dist-info → arize_phoenix-12.28.1.dist-info}/WHEEL +1 -1
  4. {arize_phoenix-10.0.4.dist-info → arize_phoenix-12.28.1.dist-info}/licenses/IP_NOTICE +1 -1
  5. phoenix/__generated__/__init__.py +0 -0
  6. phoenix/__generated__/classification_evaluator_configs/__init__.py +20 -0
  7. phoenix/__generated__/classification_evaluator_configs/_document_relevance_classification_evaluator_config.py +17 -0
  8. phoenix/__generated__/classification_evaluator_configs/_hallucination_classification_evaluator_config.py +17 -0
  9. phoenix/__generated__/classification_evaluator_configs/_models.py +18 -0
  10. phoenix/__generated__/classification_evaluator_configs/_tool_selection_classification_evaluator_config.py +17 -0
  11. phoenix/__init__.py +5 -4
  12. phoenix/auth.py +39 -2
  13. phoenix/config.py +1763 -91
  14. phoenix/datetime_utils.py +120 -2
  15. phoenix/db/README.md +595 -25
  16. phoenix/db/bulk_inserter.py +145 -103
  17. phoenix/db/engines.py +140 -33
  18. phoenix/db/enums.py +3 -12
  19. phoenix/db/facilitator.py +302 -35
  20. phoenix/db/helpers.py +1000 -65
  21. phoenix/db/iam_auth.py +64 -0
  22. phoenix/db/insertion/dataset.py +135 -2
  23. phoenix/db/insertion/document_annotation.py +9 -6
  24. phoenix/db/insertion/evaluation.py +2 -3
  25. phoenix/db/insertion/helpers.py +17 -2
  26. phoenix/db/insertion/session_annotation.py +176 -0
  27. phoenix/db/insertion/span.py +15 -11
  28. phoenix/db/insertion/span_annotation.py +3 -4
  29. phoenix/db/insertion/trace_annotation.py +3 -4
  30. phoenix/db/insertion/types.py +50 -20
  31. phoenix/db/migrations/versions/01a8342c9cdf_add_user_id_on_datasets.py +40 -0
  32. phoenix/db/migrations/versions/0df286449799_add_session_annotations_table.py +105 -0
  33. phoenix/db/migrations/versions/272b66ff50f8_drop_single_indices.py +119 -0
  34. phoenix/db/migrations/versions/58228d933c91_dataset_labels.py +67 -0
  35. phoenix/db/migrations/versions/699f655af132_experiment_tags.py +57 -0
  36. phoenix/db/migrations/versions/735d3d93c33e_add_composite_indices.py +41 -0
  37. phoenix/db/migrations/versions/a20694b15f82_cost.py +196 -0
  38. phoenix/db/migrations/versions/ab513d89518b_add_user_id_on_dataset_versions.py +40 -0
  39. phoenix/db/migrations/versions/d0690a79ea51_users_on_experiments.py +40 -0
  40. phoenix/db/migrations/versions/deb2c81c0bb2_dataset_splits.py +139 -0
  41. phoenix/db/migrations/versions/e76cbd66ffc3_add_experiments_dataset_examples.py +87 -0
  42. phoenix/db/models.py +669 -56
  43. phoenix/db/pg_config.py +10 -0
  44. phoenix/db/types/model_provider.py +4 -0
  45. phoenix/db/types/token_price_customization.py +29 -0
  46. phoenix/db/types/trace_retention.py +23 -15
  47. phoenix/experiments/evaluators/utils.py +3 -3
  48. phoenix/experiments/functions.py +160 -52
  49. phoenix/experiments/tracing.py +2 -2
  50. phoenix/experiments/types.py +1 -1
  51. phoenix/inferences/inferences.py +1 -2
  52. phoenix/server/api/auth.py +38 -7
  53. phoenix/server/api/auth_messages.py +46 -0
  54. phoenix/server/api/context.py +100 -4
  55. phoenix/server/api/dataloaders/__init__.py +79 -5
  56. phoenix/server/api/dataloaders/annotation_configs_by_project.py +31 -0
  57. phoenix/server/api/dataloaders/annotation_summaries.py +60 -8
  58. phoenix/server/api/dataloaders/average_experiment_repeated_run_group_latency.py +50 -0
  59. phoenix/server/api/dataloaders/average_experiment_run_latency.py +17 -24
  60. phoenix/server/api/dataloaders/cache/two_tier_cache.py +1 -2
  61. phoenix/server/api/dataloaders/dataset_dataset_splits.py +52 -0
  62. phoenix/server/api/dataloaders/dataset_example_revisions.py +0 -1
  63. phoenix/server/api/dataloaders/dataset_example_splits.py +40 -0
  64. phoenix/server/api/dataloaders/dataset_examples_and_versions_by_experiment_run.py +47 -0
  65. phoenix/server/api/dataloaders/dataset_labels.py +36 -0
  66. phoenix/server/api/dataloaders/document_evaluation_summaries.py +2 -2
  67. phoenix/server/api/dataloaders/document_evaluations.py +6 -9
  68. phoenix/server/api/dataloaders/experiment_annotation_summaries.py +88 -34
  69. phoenix/server/api/dataloaders/experiment_dataset_splits.py +43 -0
  70. phoenix/server/api/dataloaders/experiment_error_rates.py +21 -28
  71. phoenix/server/api/dataloaders/experiment_repeated_run_group_annotation_summaries.py +77 -0
  72. phoenix/server/api/dataloaders/experiment_repeated_run_groups.py +57 -0
  73. phoenix/server/api/dataloaders/experiment_runs_by_experiment_and_example.py +44 -0
  74. phoenix/server/api/dataloaders/last_used_times_by_generative_model_id.py +35 -0
  75. phoenix/server/api/dataloaders/latency_ms_quantile.py +40 -8
  76. phoenix/server/api/dataloaders/record_counts.py +37 -10
  77. phoenix/server/api/dataloaders/session_annotations_by_session.py +29 -0
  78. phoenix/server/api/dataloaders/span_cost_by_span.py +24 -0
  79. phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_generative_model.py +56 -0
  80. phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_project_session.py +57 -0
  81. phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_span.py +43 -0
  82. phoenix/server/api/dataloaders/span_cost_detail_summary_entries_by_trace.py +56 -0
  83. phoenix/server/api/dataloaders/span_cost_details_by_span_cost.py +27 -0
  84. phoenix/server/api/dataloaders/span_cost_summary_by_experiment.py +57 -0
  85. phoenix/server/api/dataloaders/span_cost_summary_by_experiment_repeated_run_group.py +64 -0
  86. phoenix/server/api/dataloaders/span_cost_summary_by_experiment_run.py +58 -0
  87. phoenix/server/api/dataloaders/span_cost_summary_by_generative_model.py +55 -0
  88. phoenix/server/api/dataloaders/span_cost_summary_by_project.py +152 -0
  89. phoenix/server/api/dataloaders/span_cost_summary_by_project_session.py +56 -0
  90. phoenix/server/api/dataloaders/span_cost_summary_by_trace.py +55 -0
  91. phoenix/server/api/dataloaders/span_costs.py +29 -0
  92. phoenix/server/api/dataloaders/table_fields.py +2 -2
  93. phoenix/server/api/dataloaders/token_prices_by_model.py +30 -0
  94. phoenix/server/api/dataloaders/trace_annotations_by_trace.py +27 -0
  95. phoenix/server/api/dataloaders/types.py +29 -0
  96. phoenix/server/api/exceptions.py +11 -1
  97. phoenix/server/api/helpers/dataset_helpers.py +5 -1
  98. phoenix/server/api/helpers/playground_clients.py +1243 -292
  99. phoenix/server/api/helpers/playground_registry.py +2 -2
  100. phoenix/server/api/helpers/playground_spans.py +8 -4
  101. phoenix/server/api/helpers/playground_users.py +26 -0
  102. phoenix/server/api/helpers/prompts/conversions/aws.py +83 -0
  103. phoenix/server/api/helpers/prompts/conversions/google.py +103 -0
  104. phoenix/server/api/helpers/prompts/models.py +205 -22
  105. phoenix/server/api/input_types/{SpanAnnotationFilter.py → AnnotationFilter.py} +22 -14
  106. phoenix/server/api/input_types/ChatCompletionInput.py +6 -2
  107. phoenix/server/api/input_types/CreateProjectInput.py +27 -0
  108. phoenix/server/api/input_types/CreateProjectSessionAnnotationInput.py +37 -0
  109. phoenix/server/api/input_types/DatasetFilter.py +17 -0
  110. phoenix/server/api/input_types/ExperimentRunSort.py +237 -0
  111. phoenix/server/api/input_types/GenerativeCredentialInput.py +9 -0
  112. phoenix/server/api/input_types/GenerativeModelInput.py +5 -0
  113. phoenix/server/api/input_types/ProjectSessionSort.py +161 -1
  114. phoenix/server/api/input_types/PromptFilter.py +14 -0
  115. phoenix/server/api/input_types/PromptVersionInput.py +52 -1
  116. phoenix/server/api/input_types/SpanSort.py +44 -7
  117. phoenix/server/api/input_types/TimeBinConfig.py +23 -0
  118. phoenix/server/api/input_types/UpdateAnnotationInput.py +34 -0
  119. phoenix/server/api/input_types/UserRoleInput.py +1 -0
  120. phoenix/server/api/mutations/__init__.py +10 -0
  121. phoenix/server/api/mutations/annotation_config_mutations.py +8 -8
  122. phoenix/server/api/mutations/api_key_mutations.py +19 -23
  123. phoenix/server/api/mutations/chat_mutations.py +154 -47
  124. phoenix/server/api/mutations/dataset_label_mutations.py +243 -0
  125. phoenix/server/api/mutations/dataset_mutations.py +21 -16
  126. phoenix/server/api/mutations/dataset_split_mutations.py +351 -0
  127. phoenix/server/api/mutations/experiment_mutations.py +2 -2
  128. phoenix/server/api/mutations/export_events_mutations.py +3 -3
  129. phoenix/server/api/mutations/model_mutations.py +210 -0
  130. phoenix/server/api/mutations/project_mutations.py +49 -10
  131. phoenix/server/api/mutations/project_session_annotations_mutations.py +158 -0
  132. phoenix/server/api/mutations/project_trace_retention_policy_mutations.py +8 -4
  133. phoenix/server/api/mutations/prompt_label_mutations.py +74 -65
  134. phoenix/server/api/mutations/prompt_mutations.py +65 -129
  135. phoenix/server/api/mutations/prompt_version_tag_mutations.py +11 -8
  136. phoenix/server/api/mutations/span_annotations_mutations.py +15 -10
  137. phoenix/server/api/mutations/trace_annotations_mutations.py +14 -10
  138. phoenix/server/api/mutations/trace_mutations.py +47 -3
  139. phoenix/server/api/mutations/user_mutations.py +66 -41
  140. phoenix/server/api/queries.py +768 -293
  141. phoenix/server/api/routers/__init__.py +2 -2
  142. phoenix/server/api/routers/auth.py +154 -88
  143. phoenix/server/api/routers/ldap.py +229 -0
  144. phoenix/server/api/routers/oauth2.py +369 -106
  145. phoenix/server/api/routers/v1/__init__.py +24 -4
  146. phoenix/server/api/routers/v1/annotation_configs.py +23 -31
  147. phoenix/server/api/routers/v1/annotations.py +481 -17
  148. phoenix/server/api/routers/v1/datasets.py +395 -81
  149. phoenix/server/api/routers/v1/documents.py +142 -0
  150. phoenix/server/api/routers/v1/evaluations.py +24 -31
  151. phoenix/server/api/routers/v1/experiment_evaluations.py +19 -8
  152. phoenix/server/api/routers/v1/experiment_runs.py +337 -59
  153. phoenix/server/api/routers/v1/experiments.py +479 -48
  154. phoenix/server/api/routers/v1/models.py +7 -0
  155. phoenix/server/api/routers/v1/projects.py +18 -49
  156. phoenix/server/api/routers/v1/prompts.py +54 -40
  157. phoenix/server/api/routers/v1/sessions.py +108 -0
  158. phoenix/server/api/routers/v1/spans.py +1091 -81
  159. phoenix/server/api/routers/v1/traces.py +132 -78
  160. phoenix/server/api/routers/v1/users.py +389 -0
  161. phoenix/server/api/routers/v1/utils.py +3 -7
  162. phoenix/server/api/subscriptions.py +305 -88
  163. phoenix/server/api/types/Annotation.py +90 -23
  164. phoenix/server/api/types/ApiKey.py +13 -17
  165. phoenix/server/api/types/AuthMethod.py +1 -0
  166. phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +1 -0
  167. phoenix/server/api/types/CostBreakdown.py +12 -0
  168. phoenix/server/api/types/Dataset.py +226 -72
  169. phoenix/server/api/types/DatasetExample.py +88 -18
  170. phoenix/server/api/types/DatasetExperimentAnnotationSummary.py +10 -0
  171. phoenix/server/api/types/DatasetLabel.py +57 -0
  172. phoenix/server/api/types/DatasetSplit.py +98 -0
  173. phoenix/server/api/types/DatasetVersion.py +49 -4
  174. phoenix/server/api/types/DocumentAnnotation.py +212 -0
  175. phoenix/server/api/types/Experiment.py +264 -59
  176. phoenix/server/api/types/ExperimentComparison.py +5 -10
  177. phoenix/server/api/types/ExperimentRepeatedRunGroup.py +155 -0
  178. phoenix/server/api/types/ExperimentRepeatedRunGroupAnnotationSummary.py +9 -0
  179. phoenix/server/api/types/ExperimentRun.py +169 -65
  180. phoenix/server/api/types/ExperimentRunAnnotation.py +158 -39
  181. phoenix/server/api/types/GenerativeModel.py +245 -3
  182. phoenix/server/api/types/GenerativeProvider.py +70 -11
  183. phoenix/server/api/types/{Model.py → InferenceModel.py} +1 -1
  184. phoenix/server/api/types/ModelInterface.py +16 -0
  185. phoenix/server/api/types/PlaygroundModel.py +20 -0
  186. phoenix/server/api/types/Project.py +1278 -216
  187. phoenix/server/api/types/ProjectSession.py +188 -28
  188. phoenix/server/api/types/ProjectSessionAnnotation.py +187 -0
  189. phoenix/server/api/types/ProjectTraceRetentionPolicy.py +1 -1
  190. phoenix/server/api/types/Prompt.py +119 -39
  191. phoenix/server/api/types/PromptLabel.py +42 -25
  192. phoenix/server/api/types/PromptVersion.py +11 -8
  193. phoenix/server/api/types/PromptVersionTag.py +65 -25
  194. phoenix/server/api/types/ServerStatus.py +6 -0
  195. phoenix/server/api/types/Span.py +167 -123
  196. phoenix/server/api/types/SpanAnnotation.py +189 -42
  197. phoenix/server/api/types/SpanCostDetailSummaryEntry.py +10 -0
  198. phoenix/server/api/types/SpanCostSummary.py +10 -0
  199. phoenix/server/api/types/SystemApiKey.py +65 -1
  200. phoenix/server/api/types/TokenPrice.py +16 -0
  201. phoenix/server/api/types/TokenUsage.py +3 -3
  202. phoenix/server/api/types/Trace.py +223 -51
  203. phoenix/server/api/types/TraceAnnotation.py +149 -50
  204. phoenix/server/api/types/User.py +137 -32
  205. phoenix/server/api/types/UserApiKey.py +73 -26
  206. phoenix/server/api/types/node.py +10 -0
  207. phoenix/server/api/types/pagination.py +11 -2
  208. phoenix/server/app.py +290 -45
  209. phoenix/server/authorization.py +38 -3
  210. phoenix/server/bearer_auth.py +34 -24
  211. phoenix/server/cost_tracking/cost_details_calculator.py +196 -0
  212. phoenix/server/cost_tracking/cost_model_lookup.py +179 -0
  213. phoenix/server/cost_tracking/helpers.py +68 -0
  214. phoenix/server/cost_tracking/model_cost_manifest.json +3657 -830
  215. phoenix/server/cost_tracking/regex_specificity.py +397 -0
  216. phoenix/server/cost_tracking/token_cost_calculator.py +57 -0
  217. phoenix/server/daemons/__init__.py +0 -0
  218. phoenix/server/daemons/db_disk_usage_monitor.py +214 -0
  219. phoenix/server/daemons/generative_model_store.py +103 -0
  220. phoenix/server/daemons/span_cost_calculator.py +99 -0
  221. phoenix/server/dml_event.py +17 -0
  222. phoenix/server/dml_event_handler.py +5 -0
  223. phoenix/server/email/sender.py +56 -3
  224. phoenix/server/email/templates/db_disk_usage_notification.html +19 -0
  225. phoenix/server/email/types.py +11 -0
  226. phoenix/server/experiments/__init__.py +0 -0
  227. phoenix/server/experiments/utils.py +14 -0
  228. phoenix/server/grpc_server.py +11 -11
  229. phoenix/server/jwt_store.py +17 -15
  230. phoenix/server/ldap.py +1449 -0
  231. phoenix/server/main.py +26 -10
  232. phoenix/server/oauth2.py +330 -12
  233. phoenix/server/prometheus.py +66 -6
  234. phoenix/server/rate_limiters.py +4 -9
  235. phoenix/server/retention.py +33 -20
  236. phoenix/server/session_filters.py +49 -0
  237. phoenix/server/static/.vite/manifest.json +55 -51
  238. phoenix/server/static/assets/components-BreFUQQa.js +6702 -0
  239. phoenix/server/static/assets/{index-E0M82BdE.js → index-CTQoemZv.js} +140 -56
  240. phoenix/server/static/assets/pages-DBE5iYM3.js +9524 -0
  241. phoenix/server/static/assets/vendor-BGzfc4EU.css +1 -0
  242. phoenix/server/static/assets/vendor-DCE4v-Ot.js +920 -0
  243. phoenix/server/static/assets/vendor-codemirror-D5f205eT.js +25 -0
  244. phoenix/server/static/assets/vendor-recharts-V9cwpXsm.js +37 -0
  245. phoenix/server/static/assets/vendor-shiki-Do--csgv.js +5 -0
  246. phoenix/server/static/assets/vendor-three-CmB8bl_y.js +3840 -0
  247. phoenix/server/templates/index.html +40 -6
  248. phoenix/server/thread_server.py +1 -2
  249. phoenix/server/types.py +14 -4
  250. phoenix/server/utils.py +74 -0
  251. phoenix/session/client.py +56 -3
  252. phoenix/session/data_extractor.py +5 -0
  253. phoenix/session/evaluation.py +14 -5
  254. phoenix/session/session.py +45 -9
  255. phoenix/settings.py +5 -0
  256. phoenix/trace/attributes.py +80 -13
  257. phoenix/trace/dsl/helpers.py +90 -1
  258. phoenix/trace/dsl/query.py +8 -6
  259. phoenix/trace/projects.py +5 -0
  260. phoenix/utilities/template_formatters.py +1 -1
  261. phoenix/version.py +1 -1
  262. arize_phoenix-10.0.4.dist-info/RECORD +0 -405
  263. phoenix/server/api/types/Evaluation.py +0 -39
  264. phoenix/server/cost_tracking/cost_lookup.py +0 -255
  265. phoenix/server/static/assets/components-DULKeDfL.js +0 -4365
  266. phoenix/server/static/assets/pages-Cl0A-0U2.js +0 -7430
  267. phoenix/server/static/assets/vendor-WIZid84E.css +0 -1
  268. phoenix/server/static/assets/vendor-arizeai-Dy-0mSNw.js +0 -649
  269. phoenix/server/static/assets/vendor-codemirror-DBtifKNr.js +0 -33
  270. phoenix/server/static/assets/vendor-oB4u9zuV.js +0 -905
  271. phoenix/server/static/assets/vendor-recharts-D-T4KPz2.js +0 -59
  272. phoenix/server/static/assets/vendor-shiki-BMn4O_9F.js +0 -5
  273. phoenix/server/static/assets/vendor-three-C5WAXd5r.js +0 -2998
  274. phoenix/utilities/deprecation.py +0 -31
  275. {arize_phoenix-10.0.4.dist-info → arize_phoenix-12.28.1.dist-info}/entry_points.txt +0 -0
  276. {arize_phoenix-10.0.4.dist-info → arize_phoenix-12.28.1.dist-info}/licenses/LICENSE +0 -0
@@ -3,8 +3,10 @@ from typing import Any
3
3
 
4
4
  from strawberry import Info
5
5
  from strawberry.permission import BasePermission
6
+ from typing_extensions import override
6
7
 
7
- from phoenix.server.api.exceptions import Unauthorized
8
+ from phoenix.config import get_env_support_email
9
+ from phoenix.server.api.exceptions import InsufficientStorage, Unauthorized
8
10
  from phoenix.server.bearer_auth import PhoenixUser
9
11
 
10
12
 
@@ -20,16 +22,45 @@ class IsNotReadOnly(Authorization):
20
22
  return not info.context.read_only
21
23
 
22
24
 
23
- class IsLocked(Authorization):
24
- """
25
- Disables mutations and subscriptions that create or update data but allows
26
- queries and delete mutations.
25
+ class IsNotViewer(Authorization):
26
+ message = "Viewers cannot perform this action"
27
+
28
+ def has_permission(self, source: Any, info: Info, **kwargs: Any) -> bool:
29
+ if not info.context.auth_enabled:
30
+ return True
31
+ return isinstance((user := info.context.user), PhoenixUser) and not user.is_viewer
32
+
33
+
34
+ class IsLocked(BasePermission):
27
35
  """
36
+ Permission class that restricts data-modifying operations when insufficient storage.
28
37
 
29
- message = "Operations that write or modify data are locked"
38
+ When database storage capacity is exceeded, this permission blocks mutations and
39
+ subscriptions that create or update data, while allowing queries and delete mutations
40
+ to continue. This prevents database overflow while maintaining read access and the
41
+ ability to free up space through deletions.
30
42
 
43
+ Raises:
44
+ InsufficientStorage: When storage capacity is exceeded and data operations
45
+ are temporarily disabled. The error includes guidance for resolution
46
+ and support contact information if configured.
47
+ """
48
+
49
+ @override
50
+ def on_unauthorized(self) -> None:
51
+ """Create user-friendly error message when storage operations are blocked."""
52
+ message = (
53
+ "Database operations are disabled due to insufficient storage. "
54
+ "Please delete old data or increase storage."
55
+ )
56
+ if support_email := get_env_support_email():
57
+ message += f" Need help? Contact us at {support_email}"
58
+ raise InsufficientStorage(message)
59
+
60
+ @override
31
61
  def has_permission(self, source: Any, info: Info, **kwargs: Any) -> bool:
32
- return not info.context.locked
62
+ """Check if database operations are allowed based on storage capacity and lock status."""
63
+ return not (info.context.db.should_not_insert_or_update or info.context.locked)
33
64
 
34
65
 
35
66
  MSG_ADMIN_ONLY = "Only admin can perform this action"
@@ -0,0 +1,46 @@
1
+ # ruff: noqa: E501
2
+ """
3
+ Authentication error and success message codes.
4
+
5
+ These codes are used in authentication flows to safely communicate status
6
+ to users via query parameters. Using codes instead of raw messages prevents
7
+ social engineering and phishing attacks.
8
+
9
+ The messages are passed to the frontend via window.Config to ensure a single
10
+ source of truth between backend and frontend.
11
+ """
12
+
13
+ from types import MappingProxyType
14
+ from typing import Literal, Mapping, get_args
15
+
16
+ # Error code type - used for type hints in redirect functions
17
+ AuthErrorCode = Literal[
18
+ "unknown_idp",
19
+ "auth_failed",
20
+ "invalid_state",
21
+ "unsafe_return_url",
22
+ "oauth_error",
23
+ "no_oidc_support",
24
+ "missing_email_scope",
25
+ "email_in_use",
26
+ "sign_in_not_allowed",
27
+ ]
28
+
29
+ # Error messages - passed to frontend via window.Config.authErrorMessages
30
+ # Backend generates these codes when redirecting users after OAuth errors
31
+ AUTH_ERROR_MESSAGES: Mapping[AuthErrorCode, str] = MappingProxyType(
32
+ {
33
+ "unknown_idp": "Unknown identity provider.",
34
+ "auth_failed": "Authentication failed. Please contact your administrator.",
35
+ "invalid_state": "Invalid authentication state. Please try again.",
36
+ "unsafe_return_url": "Invalid return URL. Please try again.",
37
+ "oauth_error": "Authentication failed. Please try again.",
38
+ "no_oidc_support": "Your identity provider does not appear to support OpenID Connect. Please contact your administrator.",
39
+ "missing_email_scope": "Please ensure your identity provider is configured to use the 'email' scope.",
40
+ "email_in_use": "An account with this email already exists.",
41
+ "sign_in_not_allowed": "Sign in is not allowed. Please contact your administrator.",
42
+ }
43
+ )
44
+
45
+ # Runtime assertion to ensure AUTH_ERROR_MESSAGES keys match AuthErrorCode Literal values
46
+ assert set(AUTH_ERROR_MESSAGES.keys()) == set(get_args(AuthErrorCode))
@@ -15,19 +15,29 @@ from phoenix.auth import (
15
15
  from phoenix.core.model_schema import Model
16
16
  from phoenix.db import models
17
17
  from phoenix.server.api.dataloaders import (
18
+ AnnotationConfigsByProjectDataLoader,
18
19
  AnnotationSummaryDataLoader,
20
+ AverageExperimentRepeatedRunGroupLatencyDataLoader,
19
21
  AverageExperimentRunLatencyDataLoader,
20
22
  CacheForDataLoaders,
23
+ DatasetDatasetSplitsDataLoader,
21
24
  DatasetExampleRevisionsDataLoader,
25
+ DatasetExamplesAndVersionsByExperimentRunDataLoader,
22
26
  DatasetExampleSpansDataLoader,
27
+ DatasetExampleSplitsDataLoader,
23
28
  DocumentEvaluationsDataLoader,
24
29
  DocumentEvaluationSummaryDataLoader,
25
30
  DocumentRetrievalMetricsDataLoader,
26
31
  ExperimentAnnotationSummaryDataLoader,
32
+ ExperimentDatasetSplitsDataLoader,
27
33
  ExperimentErrorRatesDataLoader,
34
+ ExperimentRepeatedRunGroupAnnotationSummariesDataLoader,
35
+ ExperimentRepeatedRunGroupsDataLoader,
28
36
  ExperimentRunAnnotations,
29
37
  ExperimentRunCountsDataLoader,
38
+ ExperimentRunsByExperimentAndExampleDataLoader,
30
39
  ExperimentSequenceNumberDataLoader,
40
+ LastUsedTimesByGenerativeModelIdDataLoader,
31
41
  LatencyMsQuantileDataLoader,
32
42
  MinStartOrMaxEndTimeDataLoader,
33
43
  NumChildSpansDataLoader,
@@ -36,6 +46,7 @@ from phoenix.server.api.dataloaders import (
36
46
  ProjectIdsByTraceRetentionPolicyIdDataLoader,
37
47
  PromptVersionSequenceNumberDataLoader,
38
48
  RecordCountDataLoader,
49
+ SessionAnnotationsBySessionDataLoader,
39
50
  SessionIODataLoader,
40
51
  SessionNumTracesDataLoader,
41
52
  SessionNumTracesWithErrorDataLoader,
@@ -43,18 +54,35 @@ from phoenix.server.api.dataloaders import (
43
54
  SessionTraceLatencyMsQuantileDataLoader,
44
55
  SpanAnnotationsDataLoader,
45
56
  SpanByIdDataLoader,
57
+ SpanCostBySpanDataLoader,
58
+ SpanCostDetailsBySpanCostDataLoader,
59
+ SpanCostDetailSummaryEntriesByGenerativeModelDataLoader,
60
+ SpanCostDetailSummaryEntriesByProjectSessionDataLoader,
61
+ SpanCostDetailSummaryEntriesBySpanDataLoader,
62
+ SpanCostDetailSummaryEntriesByTraceDataLoader,
63
+ SpanCostSummaryByExperimentDataLoader,
64
+ SpanCostSummaryByExperimentRepeatedRunGroupDataLoader,
65
+ SpanCostSummaryByExperimentRunDataLoader,
66
+ SpanCostSummaryByGenerativeModelDataLoader,
67
+ SpanCostSummaryByProjectDataLoader,
68
+ SpanCostSummaryByProjectSessionDataLoader,
69
+ SpanCostSummaryByTraceDataLoader,
46
70
  SpanDatasetExamplesDataLoader,
47
71
  SpanDescendantsDataLoader,
48
72
  SpanProjectsDataLoader,
49
73
  TableFieldsDataLoader,
50
74
  TokenCountDataLoader,
75
+ TokenPricesByModelDataLoader,
76
+ TraceAnnotationsByTraceDataLoader,
51
77
  TraceByTraceIdsDataLoader,
52
78
  TraceRetentionPolicyIdByProjectIdDataLoader,
53
79
  TraceRootSpansDataLoader,
54
80
  UserRolesDataLoader,
55
81
  UsersDataLoader,
56
82
  )
83
+ from phoenix.server.api.dataloaders.dataset_labels import DatasetLabelsDataLoader
57
84
  from phoenix.server.bearer_auth import PhoenixUser
85
+ from phoenix.server.daemons.span_cost_calculator import SpanCostCalculator
58
86
  from phoenix.server.dml_event import DmlEvent
59
87
  from phoenix.server.email.types import EmailSender
60
88
  from phoenix.server.types import (
@@ -68,47 +96,107 @@ from phoenix.server.types import (
68
96
 
69
97
  @dataclass
70
98
  class DataLoaders:
99
+ annotation_configs_by_project: AnnotationConfigsByProjectDataLoader
100
+ annotation_summaries: AnnotationSummaryDataLoader
101
+ average_experiment_repeated_run_group_latency: (
102
+ AverageExperimentRepeatedRunGroupLatencyDataLoader
103
+ )
71
104
  average_experiment_run_latency: AverageExperimentRunLatencyDataLoader
105
+ dataset_example_fields: TableFieldsDataLoader
72
106
  dataset_example_revisions: DatasetExampleRevisionsDataLoader
73
107
  dataset_example_spans: DatasetExampleSpansDataLoader
108
+ dataset_labels: DatasetLabelsDataLoader
109
+ dataset_label_fields: TableFieldsDataLoader
110
+ dataset_dataset_splits: DatasetDatasetSplitsDataLoader
111
+ dataset_examples_and_versions_by_experiment_run: (
112
+ DatasetExamplesAndVersionsByExperimentRunDataLoader
113
+ )
114
+ dataset_example_splits: DatasetExampleSplitsDataLoader
115
+ dataset_fields: TableFieldsDataLoader
116
+ dataset_split_fields: TableFieldsDataLoader
117
+ dataset_version_fields: TableFieldsDataLoader
118
+ document_annotation_fields: TableFieldsDataLoader
74
119
  document_evaluation_summaries: DocumentEvaluationSummaryDataLoader
75
120
  document_evaluations: DocumentEvaluationsDataLoader
76
121
  document_retrieval_metrics: DocumentRetrievalMetricsDataLoader
77
- annotation_summaries: AnnotationSummaryDataLoader
78
122
  experiment_annotation_summaries: ExperimentAnnotationSummaryDataLoader
123
+ experiment_dataset_splits: ExperimentDatasetSplitsDataLoader
79
124
  experiment_error_rates: ExperimentErrorRatesDataLoader
125
+ experiment_fields: TableFieldsDataLoader
126
+ experiment_repeated_run_group_annotation_summaries: (
127
+ ExperimentRepeatedRunGroupAnnotationSummariesDataLoader
128
+ )
129
+ experiment_repeated_run_groups: ExperimentRepeatedRunGroupsDataLoader
130
+ experiment_run_annotation_fields: TableFieldsDataLoader
80
131
  experiment_run_annotations: ExperimentRunAnnotations
81
132
  experiment_run_counts: ExperimentRunCountsDataLoader
133
+ experiment_run_fields: TableFieldsDataLoader
134
+ experiment_runs_by_experiment_and_example: ExperimentRunsByExperimentAndExampleDataLoader
82
135
  experiment_sequence_number: ExperimentSequenceNumberDataLoader
136
+ generative_model_fields: TableFieldsDataLoader
137
+ last_used_times_by_generative_model_id: LastUsedTimesByGenerativeModelIdDataLoader
83
138
  latency_ms_quantile: LatencyMsQuantileDataLoader
84
139
  min_start_or_max_end_times: MinStartOrMaxEndTimeDataLoader
85
140
  num_child_spans: NumChildSpansDataLoader
86
141
  num_spans_per_trace: NumSpansPerTraceDataLoader
142
+ project_by_name: ProjectByNameDataLoader
87
143
  project_fields: TableFieldsDataLoader
144
+ project_trace_retention_policy_fields: TableFieldsDataLoader
88
145
  projects_by_trace_retention_policy_id: ProjectIdsByTraceRetentionPolicyIdDataLoader
146
+ prompt_fields: TableFieldsDataLoader
147
+ prompt_label_fields: TableFieldsDataLoader
89
148
  prompt_version_sequence_number: PromptVersionSequenceNumberDataLoader
149
+ prompt_version_tag_fields: TableFieldsDataLoader
150
+ project_session_annotation_fields: TableFieldsDataLoader
151
+ project_session_fields: TableFieldsDataLoader
90
152
  record_counts: RecordCountDataLoader
153
+ session_annotations_by_session: SessionAnnotationsBySessionDataLoader
91
154
  session_first_inputs: SessionIODataLoader
92
155
  session_last_outputs: SessionIODataLoader
93
156
  session_num_traces: SessionNumTracesDataLoader
94
157
  session_num_traces_with_error: SessionNumTracesWithErrorDataLoader
95
158
  session_token_usages: SessionTokenUsagesDataLoader
96
159
  session_trace_latency_ms_quantile: SessionTraceLatencyMsQuantileDataLoader
160
+ span_annotation_fields: TableFieldsDataLoader
97
161
  span_annotations: SpanAnnotationsDataLoader
98
162
  span_by_id: SpanByIdDataLoader
163
+ span_cost_by_span: SpanCostBySpanDataLoader
164
+ span_cost_detail_fields: TableFieldsDataLoader
165
+ span_cost_detail_summary_entries_by_generative_model: (
166
+ SpanCostDetailSummaryEntriesByGenerativeModelDataLoader
167
+ )
168
+ span_cost_detail_summary_entries_by_project_session: (
169
+ SpanCostDetailSummaryEntriesByProjectSessionDataLoader
170
+ )
171
+ span_cost_detail_summary_entries_by_span: SpanCostDetailSummaryEntriesBySpanDataLoader
172
+ span_cost_detail_summary_entries_by_trace: SpanCostDetailSummaryEntriesByTraceDataLoader
173
+ span_cost_details_by_span_cost: SpanCostDetailsBySpanCostDataLoader
174
+ span_cost_fields: TableFieldsDataLoader
175
+ span_cost_summary_by_experiment: SpanCostSummaryByExperimentDataLoader
176
+ span_cost_summary_by_experiment_repeated_run_group: (
177
+ SpanCostSummaryByExperimentRepeatedRunGroupDataLoader
178
+ )
179
+ span_cost_summary_by_experiment_run: SpanCostSummaryByExperimentRunDataLoader
180
+ span_cost_summary_by_generative_model: SpanCostSummaryByGenerativeModelDataLoader
181
+ span_cost_summary_by_project: SpanCostSummaryByProjectDataLoader
182
+ span_cost_summary_by_project_session: SpanCostSummaryByProjectSessionDataLoader
183
+ span_cost_summary_by_trace: SpanCostSummaryByTraceDataLoader
99
184
  span_dataset_examples: SpanDatasetExamplesDataLoader
100
185
  span_descendants: SpanDescendantsDataLoader
101
186
  span_fields: TableFieldsDataLoader
102
187
  span_projects: SpanProjectsDataLoader
103
188
  token_counts: TokenCountDataLoader
189
+ token_prices_by_model: TokenPricesByModelDataLoader
190
+ trace_annotation_fields: TableFieldsDataLoader
191
+ trace_annotations_by_trace: TraceAnnotationsByTraceDataLoader
104
192
  trace_by_trace_ids: TraceByTraceIdsDataLoader
105
193
  trace_fields: TableFieldsDataLoader
106
194
  trace_retention_policy_id_by_project_id: TraceRetentionPolicyIdByProjectIdDataLoader
107
- project_trace_retention_policy_fields: TableFieldsDataLoader
108
195
  trace_root_spans: TraceRootSpansDataLoader
109
- project_by_name: ProjectByNameDataLoader
110
- users: UsersDataLoader
111
196
  user_roles: UserRolesDataLoader
197
+ user_api_key_fields: TableFieldsDataLoader
198
+ user_fields: TableFieldsDataLoader
199
+ users: UsersDataLoader
112
200
 
113
201
 
114
202
  class _NoOp:
@@ -123,6 +211,7 @@ class Context(BaseContext):
123
211
  cache_for_dataloaders: Optional[CacheForDataLoaders]
124
212
  model: Model
125
213
  export_path: Path
214
+ span_cost_calculator: SpanCostCalculator
126
215
  last_updated_at: CanGetLastUpdatedAt = _NoOp()
127
216
  event_queue: CanPutItem[DmlEvent] = _NoOp()
128
217
  corpus: Optional[Model] = None
@@ -181,3 +270,10 @@ class Context(BaseContext):
181
270
  @cached_property
182
271
  def user(self) -> PhoenixUser:
183
272
  return cast(PhoenixUser, self.get_request().user)
273
+
274
+ @cached_property
275
+ def user_id(self) -> Optional[int]:
276
+ try:
277
+ return int(self.user.identity)
278
+ except Exception:
279
+ return None
@@ -1,9 +1,23 @@
1
1
  from dataclasses import dataclass, field
2
2
 
3
+ from phoenix.server.api.dataloaders.span_cost_detail_summary_entries_by_project_session import (
4
+ SpanCostDetailSummaryEntriesByProjectSessionDataLoader,
5
+ )
6
+
7
+ from .annotation_configs_by_project import AnnotationConfigsByProjectDataLoader
3
8
  from .annotation_summaries import AnnotationSummaryCache, AnnotationSummaryDataLoader
9
+ from .average_experiment_repeated_run_group_latency import (
10
+ AverageExperimentRepeatedRunGroupLatencyDataLoader,
11
+ )
4
12
  from .average_experiment_run_latency import AverageExperimentRunLatencyDataLoader
13
+ from .dataset_dataset_splits import DatasetDatasetSplitsDataLoader
5
14
  from .dataset_example_revisions import DatasetExampleRevisionsDataLoader
6
15
  from .dataset_example_spans import DatasetExampleSpansDataLoader
16
+ from .dataset_example_splits import DatasetExampleSplitsDataLoader
17
+ from .dataset_examples_and_versions_by_experiment_run import (
18
+ DatasetExamplesAndVersionsByExperimentRunDataLoader,
19
+ )
20
+ from .dataset_labels import DatasetLabelsDataLoader
7
21
  from .document_evaluation_summaries import (
8
22
  DocumentEvaluationSummaryCache,
9
23
  DocumentEvaluationSummaryDataLoader,
@@ -11,10 +25,19 @@ from .document_evaluation_summaries import (
11
25
  from .document_evaluations import DocumentEvaluationsDataLoader
12
26
  from .document_retrieval_metrics import DocumentRetrievalMetricsDataLoader
13
27
  from .experiment_annotation_summaries import ExperimentAnnotationSummaryDataLoader
28
+ from .experiment_dataset_splits import ExperimentDatasetSplitsDataLoader
14
29
  from .experiment_error_rates import ExperimentErrorRatesDataLoader
30
+ from .experiment_repeated_run_group_annotation_summaries import (
31
+ ExperimentRepeatedRunGroupAnnotationSummariesDataLoader,
32
+ )
33
+ from .experiment_repeated_run_groups import ExperimentRepeatedRunGroupsDataLoader
15
34
  from .experiment_run_annotations import ExperimentRunAnnotations
16
35
  from .experiment_run_counts import ExperimentRunCountsDataLoader
36
+ from .experiment_runs_by_experiment_and_example import (
37
+ ExperimentRunsByExperimentAndExampleDataLoader,
38
+ )
17
39
  from .experiment_sequence_number import ExperimentSequenceNumberDataLoader
40
+ from .last_used_times_by_generative_model_id import LastUsedTimesByGenerativeModelIdDataLoader
18
41
  from .latency_ms_quantile import LatencyMsQuantileCache, LatencyMsQuantileDataLoader
19
42
  from .min_start_or_max_end_times import MinStartOrMaxEndTimeCache, MinStartOrMaxEndTimeDataLoader
20
43
  from .num_child_spans import NumChildSpansDataLoader
@@ -23,6 +46,7 @@ from .project_by_name import ProjectByNameDataLoader
23
46
  from .project_ids_by_trace_retention_policy_id import ProjectIdsByTraceRetentionPolicyIdDataLoader
24
47
  from .prompt_version_sequence_number import PromptVersionSequenceNumberDataLoader
25
48
  from .record_counts import RecordCountCache, RecordCountDataLoader
49
+ from .session_annotations_by_session import SessionAnnotationsBySessionDataLoader
26
50
  from .session_io import SessionIODataLoader
27
51
  from .session_num_traces import SessionNumTracesDataLoader
28
52
  from .session_num_traces_with_error import SessionNumTracesWithErrorDataLoader
@@ -30,11 +54,30 @@ from .session_token_usages import SessionTokenUsagesDataLoader
30
54
  from .session_trace_latency_ms_quantile import SessionTraceLatencyMsQuantileDataLoader
31
55
  from .span_annotations import SpanAnnotationsDataLoader
32
56
  from .span_by_id import SpanByIdDataLoader
57
+ from .span_cost_by_span import SpanCostBySpanDataLoader
58
+ from .span_cost_detail_summary_entries_by_generative_model import (
59
+ SpanCostDetailSummaryEntriesByGenerativeModelDataLoader,
60
+ )
61
+ from .span_cost_detail_summary_entries_by_span import SpanCostDetailSummaryEntriesBySpanDataLoader
62
+ from .span_cost_detail_summary_entries_by_trace import SpanCostDetailSummaryEntriesByTraceDataLoader
63
+ from .span_cost_details_by_span_cost import SpanCostDetailsBySpanCostDataLoader
64
+ from .span_cost_summary_by_experiment import SpanCostSummaryByExperimentDataLoader
65
+ from .span_cost_summary_by_experiment_repeated_run_group import (
66
+ SpanCostSummaryByExperimentRepeatedRunGroupDataLoader,
67
+ )
68
+ from .span_cost_summary_by_experiment_run import SpanCostSummaryByExperimentRunDataLoader
69
+ from .span_cost_summary_by_generative_model import SpanCostSummaryByGenerativeModelDataLoader
70
+ from .span_cost_summary_by_project import SpanCostSummaryByProjectDataLoader, SpanCostSummaryCache
71
+ from .span_cost_summary_by_project_session import SpanCostSummaryByProjectSessionDataLoader
72
+ from .span_cost_summary_by_trace import SpanCostSummaryByTraceDataLoader
73
+ from .span_costs import SpanCostsDataLoader
33
74
  from .span_dataset_examples import SpanDatasetExamplesDataLoader
34
75
  from .span_descendants import SpanDescendantsDataLoader
35
76
  from .span_projects import SpanProjectsDataLoader
36
77
  from .table_fields import TableFieldsDataLoader
37
78
  from .token_counts import TokenCountCache, TokenCountDataLoader
79
+ from .token_prices_by_model import TokenPricesByModelDataLoader
80
+ from .trace_annotations_by_trace import TraceAnnotationsByTraceDataLoader
38
81
  from .trace_by_trace_ids import TraceByTraceIdsDataLoader
39
82
  from .trace_retention_policy_id_by_project_id import TraceRetentionPolicyIdByProjectIdDataLoader
40
83
  from .trace_root_spans import TraceRootSpansDataLoader
@@ -42,44 +85,72 @@ from .user_roles import UserRolesDataLoader
42
85
  from .users import UsersDataLoader
43
86
 
44
87
  __all__ = [
45
- "CacheForDataLoaders",
88
+ "AnnotationConfigsByProjectDataLoader",
89
+ "AnnotationSummaryDataLoader",
90
+ "AverageExperimentRepeatedRunGroupLatencyDataLoader",
46
91
  "AverageExperimentRunLatencyDataLoader",
92
+ "CacheForDataLoaders",
93
+ "DatasetDatasetSplitsDataLoader",
47
94
  "DatasetExampleRevisionsDataLoader",
48
95
  "DatasetExampleSpansDataLoader",
96
+ "DatasetExamplesAndVersionsByExperimentRunDataLoader",
97
+ "DatasetExampleSplitsDataLoader",
98
+ "DatasetLabelsDataLoader",
99
+ "ExperimentDatasetSplitsDataLoader",
49
100
  "DocumentEvaluationSummaryDataLoader",
50
101
  "DocumentEvaluationsDataLoader",
51
102
  "DocumentRetrievalMetricsDataLoader",
52
- "AnnotationSummaryDataLoader",
53
103
  "ExperimentAnnotationSummaryDataLoader",
54
104
  "ExperimentErrorRatesDataLoader",
105
+ "ExperimentRepeatedRunGroupsDataLoader",
106
+ "ExperimentRepeatedRunGroupAnnotationSummariesDataLoader",
55
107
  "ExperimentRunAnnotations",
56
108
  "ExperimentRunCountsDataLoader",
109
+ "ExperimentRunsByExperimentAndExampleDataLoader",
57
110
  "ExperimentSequenceNumberDataLoader",
111
+ "LastUsedTimesByGenerativeModelIdDataLoader",
58
112
  "LatencyMsQuantileDataLoader",
59
113
  "MinStartOrMaxEndTimeDataLoader",
60
114
  "NumChildSpansDataLoader",
61
115
  "NumSpansPerTraceDataLoader",
116
+ "ProjectByNameDataLoader",
62
117
  "ProjectIdsByTraceRetentionPolicyIdDataLoader",
63
118
  "PromptVersionSequenceNumberDataLoader",
64
119
  "RecordCountDataLoader",
120
+ "SessionAnnotationsBySessionDataLoader",
65
121
  "SessionIODataLoader",
66
122
  "SessionNumTracesDataLoader",
67
123
  "SessionNumTracesWithErrorDataLoader",
68
124
  "SessionTokenUsagesDataLoader",
69
125
  "SessionTraceLatencyMsQuantileDataLoader",
126
+ "SpanAnnotationsDataLoader",
70
127
  "SpanByIdDataLoader",
128
+ "SpanCostBySpanDataLoader",
129
+ "SpanCostDetailSummaryEntriesByGenerativeModelDataLoader",
130
+ "SpanCostDetailSummaryEntriesByProjectSessionDataLoader",
131
+ "SpanCostDetailSummaryEntriesBySpanDataLoader",
132
+ "SpanCostDetailSummaryEntriesByTraceDataLoader",
133
+ "SpanCostDetailsBySpanCostDataLoader",
134
+ "SpanCostSummaryByExperimentDataLoader",
135
+ "SpanCostSummaryByExperimentRepeatedRunGroupDataLoader",
136
+ "SpanCostSummaryByExperimentRunDataLoader",
137
+ "SpanCostSummaryByGenerativeModelDataLoader",
138
+ "SpanCostSummaryByProjectDataLoader",
139
+ "SpanCostSummaryByProjectSessionDataLoader",
140
+ "SpanCostSummaryByTraceDataLoader",
141
+ "SpanCostsDataLoader",
71
142
  "SpanDatasetExamplesDataLoader",
72
143
  "SpanDescendantsDataLoader",
73
144
  "SpanProjectsDataLoader",
74
145
  "TableFieldsDataLoader",
75
146
  "TokenCountDataLoader",
147
+ "TokenPricesByModelDataLoader",
148
+ "TraceAnnotationsByTraceDataLoader",
76
149
  "TraceByTraceIdsDataLoader",
77
150
  "TraceRetentionPolicyIdByProjectIdDataLoader",
78
151
  "TraceRootSpansDataLoader",
79
- "ProjectByNameDataLoader",
80
- "SpanAnnotationsDataLoader",
81
- "UsersDataLoader",
82
152
  "UserRolesDataLoader",
153
+ "UsersDataLoader",
83
154
  ]
84
155
 
85
156
 
@@ -103,3 +174,6 @@ class CacheForDataLoaders:
103
174
  token_count: TokenCountCache = field(
104
175
  default_factory=TokenCountCache,
105
176
  )
177
+ token_cost: SpanCostSummaryCache = field(
178
+ default_factory=SpanCostSummaryCache,
179
+ )
@@ -0,0 +1,31 @@
1
+ from collections import defaultdict
2
+
3
+ from sqlalchemy import select
4
+ from strawberry.dataloader import DataLoader
5
+ from typing_extensions import TypeAlias
6
+
7
+ from phoenix.db import models
8
+ from phoenix.server.types import DbSessionFactory
9
+
10
+ ProjectId: TypeAlias = int
11
+ Key: TypeAlias = ProjectId
12
+ Result: TypeAlias = tuple[models.AnnotationConfig, ...]
13
+
14
+
15
+ class AnnotationConfigsByProjectDataLoader(DataLoader[Key, Result]):
16
+ def __init__(self, db: DbSessionFactory) -> None:
17
+ super().__init__(load_fn=self._load_fn)
18
+ self._db = db
19
+
20
+ async def _load_fn(self, keys: list[Key]) -> list[Result]:
21
+ stmt = (
22
+ select(models.ProjectAnnotationConfig.project_id, models.AnnotationConfig)
23
+ .join_from(models.ProjectAnnotationConfig, models.AnnotationConfig)
24
+ .where(models.ProjectAnnotationConfig.project_id.in_(keys))
25
+ )
26
+ results: defaultdict[Key, list[models.AnnotationConfig]] = defaultdict(list)
27
+ async with self._db() as session:
28
+ data = await session.stream(stmt)
29
+ async for id_, config in data:
30
+ results[id_].append(config)
31
+ return [tuple(results[k]) for k in keys]
@@ -13,6 +13,7 @@ from phoenix.db import models
13
13
  from phoenix.server.api.dataloaders.cache import TwoTierCache
14
14
  from phoenix.server.api.input_types.TimeRange import TimeRange
15
15
  from phoenix.server.api.types.AnnotationSummary import AnnotationSummary
16
+ from phoenix.server.session_filters import get_filtered_session_rowids_subquery
16
17
  from phoenix.server.types import DbSessionFactory
17
18
  from phoenix.trace.dsl import SpanFilter
18
19
 
@@ -20,27 +21,41 @@ Kind: TypeAlias = Literal["span", "trace"]
20
21
  ProjectRowId: TypeAlias = int
21
22
  TimeInterval: TypeAlias = tuple[Optional[datetime], Optional[datetime]]
22
23
  FilterCondition: TypeAlias = Optional[str]
24
+ SessionFilterCondition: TypeAlias = Optional[str]
23
25
  AnnotationName: TypeAlias = str
24
26
 
25
- Segment: TypeAlias = tuple[Kind, ProjectRowId, TimeInterval, FilterCondition]
27
+ Segment: TypeAlias = tuple[
28
+ Kind,
29
+ ProjectRowId,
30
+ TimeInterval,
31
+ FilterCondition,
32
+ SessionFilterCondition,
33
+ ]
26
34
  Param: TypeAlias = AnnotationName
27
35
 
28
- Key: TypeAlias = tuple[Kind, ProjectRowId, Optional[TimeRange], FilterCondition, AnnotationName]
36
+ Key: TypeAlias = tuple[
37
+ Kind,
38
+ ProjectRowId,
39
+ Optional[TimeRange],
40
+ FilterCondition,
41
+ SessionFilterCondition,
42
+ AnnotationName,
43
+ ]
29
44
  Result: TypeAlias = Optional[AnnotationSummary]
30
45
  ResultPosition: TypeAlias = int
31
46
  DEFAULT_VALUE: Result = None
32
47
 
33
48
 
34
49
  def _cache_key_fn(key: Key) -> tuple[Segment, Param]:
35
- kind, project_rowid, time_range, filter_condition, eval_name = key
50
+ kind, project_rowid, time_range, filter_condition, session_filter_condition, eval_name = key
36
51
  interval = (
37
52
  (time_range.start, time_range.end) if isinstance(time_range, TimeRange) else (None, None)
38
53
  )
39
- return (kind, project_rowid, interval, filter_condition), eval_name
54
+ return (kind, project_rowid, interval, filter_condition, session_filter_condition), eval_name
40
55
 
41
56
 
42
57
  _Section: TypeAlias = tuple[ProjectRowId, AnnotationName, Kind]
43
- _SubKey: TypeAlias = tuple[TimeInterval, FilterCondition]
58
+ _SubKey: TypeAlias = tuple[TimeInterval, FilterCondition, SessionFilterCondition]
44
59
 
45
60
 
46
61
  class AnnotationSummaryCache(
@@ -61,8 +76,21 @@ class AnnotationSummaryCache(
61
76
  del self._cache[section]
62
77
 
63
78
  def _cache_key(self, key: Key) -> tuple[_Section, _SubKey]:
64
- (kind, project_rowid, interval, filter_condition), annotation_name = _cache_key_fn(key)
65
- return (project_rowid, annotation_name, kind), (interval, filter_condition)
79
+ (
80
+ (
81
+ kind,
82
+ project_rowid,
83
+ interval,
84
+ filter_condition,
85
+ session_filter_condition,
86
+ ),
87
+ annotation_name,
88
+ ) = _cache_key_fn(key)
89
+ return (project_rowid, annotation_name, kind), (
90
+ interval,
91
+ filter_condition,
92
+ session_filter_condition,
93
+ )
66
94
 
67
95
 
68
96
  class AnnotationSummaryDataLoader(DataLoader[Key, Result]):
@@ -102,7 +130,9 @@ def _get_stmt(
102
130
  segment: Segment,
103
131
  *annotation_names: Param,
104
132
  ) -> Select[Any]:
105
- kind, project_rowid, (start_time, end_time), filter_condition = segment
133
+ kind, project_rowid, (start_time, end_time), filter_condition, session_filter_condition = (
134
+ segment
135
+ )
106
136
 
107
137
  annotation_model: Union[Type[models.SpanAnnotation], Type[models.TraceAnnotation]]
108
138
  entity_model: Union[Type[models.Span], Type[models.Trace]]
@@ -144,6 +174,19 @@ def _get_stmt(
144
174
  entity_count_query = entity_count_query.where(
145
175
  cast(Type[models.Trace], entity_model).project_rowid == project_rowid
146
176
  )
177
+ else:
178
+ assert_never(kind)
179
+
180
+ if session_filter_condition:
181
+ filtered_session_rowids = get_filtered_session_rowids_subquery(
182
+ session_filter_condition=session_filter_condition,
183
+ project_rowids=[project_rowid],
184
+ start_time=start_time,
185
+ end_time=end_time,
186
+ )
187
+ entity_count_query = entity_count_query.where(
188
+ models.Trace.project_session_rowid.in_(filtered_session_rowids)
189
+ )
147
190
 
148
191
  entity_count_query = entity_count_query.where(
149
192
  or_(score_column.is_not(None), label_column.is_not(None))
@@ -186,6 +229,15 @@ def _get_stmt(
186
229
  else:
187
230
  assert_never(kind)
188
231
 
232
+ if session_filter_condition:
233
+ filtered_session_rowids = get_filtered_session_rowids_subquery(
234
+ session_filter_condition=session_filter_condition,
235
+ project_rowids=[project_rowid],
236
+ start_time=start_time,
237
+ end_time=end_time,
238
+ )
239
+ base_stmt = base_stmt.where(models.Trace.project_session_rowid.in_(filtered_session_rowids))
240
+
189
241
  base_stmt = base_stmt.where(or_(score_column.is_not(None), label_column.is_not(None)))
190
242
  base_stmt = base_stmt.where(name_column.in_(annotation_names))
191
243