arize-phoenix 11.23.1__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 (221) hide show
  1. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/METADATA +61 -36
  2. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/RECORD +212 -162
  3. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/WHEEL +1 -1
  4. {arize_phoenix-11.23.1.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 +2 -1
  12. phoenix/auth.py +27 -2
  13. phoenix/config.py +1594 -81
  14. phoenix/db/README.md +546 -28
  15. phoenix/db/bulk_inserter.py +119 -116
  16. phoenix/db/engines.py +140 -33
  17. phoenix/db/facilitator.py +22 -1
  18. phoenix/db/helpers.py +818 -65
  19. phoenix/db/iam_auth.py +64 -0
  20. phoenix/db/insertion/dataset.py +133 -1
  21. phoenix/db/insertion/document_annotation.py +9 -6
  22. phoenix/db/insertion/evaluation.py +2 -3
  23. phoenix/db/insertion/helpers.py +2 -2
  24. phoenix/db/insertion/session_annotation.py +176 -0
  25. phoenix/db/insertion/span_annotation.py +3 -4
  26. phoenix/db/insertion/trace_annotation.py +3 -4
  27. phoenix/db/insertion/types.py +41 -18
  28. phoenix/db/migrations/versions/01a8342c9cdf_add_user_id_on_datasets.py +40 -0
  29. phoenix/db/migrations/versions/0df286449799_add_session_annotations_table.py +105 -0
  30. phoenix/db/migrations/versions/272b66ff50f8_drop_single_indices.py +119 -0
  31. phoenix/db/migrations/versions/58228d933c91_dataset_labels.py +67 -0
  32. phoenix/db/migrations/versions/699f655af132_experiment_tags.py +57 -0
  33. phoenix/db/migrations/versions/735d3d93c33e_add_composite_indices.py +41 -0
  34. phoenix/db/migrations/versions/ab513d89518b_add_user_id_on_dataset_versions.py +40 -0
  35. phoenix/db/migrations/versions/d0690a79ea51_users_on_experiments.py +40 -0
  36. phoenix/db/migrations/versions/deb2c81c0bb2_dataset_splits.py +139 -0
  37. phoenix/db/migrations/versions/e76cbd66ffc3_add_experiments_dataset_examples.py +87 -0
  38. phoenix/db/models.py +364 -56
  39. phoenix/db/pg_config.py +10 -0
  40. phoenix/db/types/trace_retention.py +7 -6
  41. phoenix/experiments/functions.py +69 -19
  42. phoenix/inferences/inferences.py +1 -2
  43. phoenix/server/api/auth.py +9 -0
  44. phoenix/server/api/auth_messages.py +46 -0
  45. phoenix/server/api/context.py +60 -0
  46. phoenix/server/api/dataloaders/__init__.py +36 -0
  47. phoenix/server/api/dataloaders/annotation_summaries.py +60 -8
  48. phoenix/server/api/dataloaders/average_experiment_repeated_run_group_latency.py +50 -0
  49. phoenix/server/api/dataloaders/average_experiment_run_latency.py +17 -24
  50. phoenix/server/api/dataloaders/cache/two_tier_cache.py +1 -2
  51. phoenix/server/api/dataloaders/dataset_dataset_splits.py +52 -0
  52. phoenix/server/api/dataloaders/dataset_example_revisions.py +0 -1
  53. phoenix/server/api/dataloaders/dataset_example_splits.py +40 -0
  54. phoenix/server/api/dataloaders/dataset_examples_and_versions_by_experiment_run.py +47 -0
  55. phoenix/server/api/dataloaders/dataset_labels.py +36 -0
  56. phoenix/server/api/dataloaders/document_evaluation_summaries.py +2 -2
  57. phoenix/server/api/dataloaders/document_evaluations.py +6 -9
  58. phoenix/server/api/dataloaders/experiment_annotation_summaries.py +88 -34
  59. phoenix/server/api/dataloaders/experiment_dataset_splits.py +43 -0
  60. phoenix/server/api/dataloaders/experiment_error_rates.py +21 -28
  61. phoenix/server/api/dataloaders/experiment_repeated_run_group_annotation_summaries.py +77 -0
  62. phoenix/server/api/dataloaders/experiment_repeated_run_groups.py +57 -0
  63. phoenix/server/api/dataloaders/experiment_runs_by_experiment_and_example.py +44 -0
  64. phoenix/server/api/dataloaders/latency_ms_quantile.py +40 -8
  65. phoenix/server/api/dataloaders/record_counts.py +37 -10
  66. phoenix/server/api/dataloaders/session_annotations_by_session.py +29 -0
  67. phoenix/server/api/dataloaders/span_cost_summary_by_experiment_repeated_run_group.py +64 -0
  68. phoenix/server/api/dataloaders/span_cost_summary_by_project.py +28 -14
  69. phoenix/server/api/dataloaders/span_costs.py +3 -9
  70. phoenix/server/api/dataloaders/table_fields.py +2 -2
  71. phoenix/server/api/dataloaders/token_prices_by_model.py +30 -0
  72. phoenix/server/api/dataloaders/trace_annotations_by_trace.py +27 -0
  73. phoenix/server/api/exceptions.py +5 -1
  74. phoenix/server/api/helpers/playground_clients.py +263 -83
  75. phoenix/server/api/helpers/playground_spans.py +2 -1
  76. phoenix/server/api/helpers/playground_users.py +26 -0
  77. phoenix/server/api/helpers/prompts/conversions/google.py +103 -0
  78. phoenix/server/api/helpers/prompts/models.py +61 -19
  79. phoenix/server/api/input_types/{SpanAnnotationFilter.py → AnnotationFilter.py} +22 -14
  80. phoenix/server/api/input_types/ChatCompletionInput.py +3 -0
  81. phoenix/server/api/input_types/CreateProjectSessionAnnotationInput.py +37 -0
  82. phoenix/server/api/input_types/DatasetFilter.py +5 -2
  83. phoenix/server/api/input_types/ExperimentRunSort.py +237 -0
  84. phoenix/server/api/input_types/GenerativeModelInput.py +3 -0
  85. phoenix/server/api/input_types/ProjectSessionSort.py +158 -1
  86. phoenix/server/api/input_types/PromptVersionInput.py +47 -1
  87. phoenix/server/api/input_types/SpanSort.py +3 -2
  88. phoenix/server/api/input_types/UpdateAnnotationInput.py +34 -0
  89. phoenix/server/api/input_types/UserRoleInput.py +1 -0
  90. phoenix/server/api/mutations/__init__.py +8 -0
  91. phoenix/server/api/mutations/annotation_config_mutations.py +8 -8
  92. phoenix/server/api/mutations/api_key_mutations.py +15 -20
  93. phoenix/server/api/mutations/chat_mutations.py +106 -37
  94. phoenix/server/api/mutations/dataset_label_mutations.py +243 -0
  95. phoenix/server/api/mutations/dataset_mutations.py +21 -16
  96. phoenix/server/api/mutations/dataset_split_mutations.py +351 -0
  97. phoenix/server/api/mutations/experiment_mutations.py +2 -2
  98. phoenix/server/api/mutations/export_events_mutations.py +3 -3
  99. phoenix/server/api/mutations/model_mutations.py +11 -9
  100. phoenix/server/api/mutations/project_mutations.py +4 -4
  101. phoenix/server/api/mutations/project_session_annotations_mutations.py +158 -0
  102. phoenix/server/api/mutations/project_trace_retention_policy_mutations.py +8 -4
  103. phoenix/server/api/mutations/prompt_label_mutations.py +74 -65
  104. phoenix/server/api/mutations/prompt_mutations.py +65 -129
  105. phoenix/server/api/mutations/prompt_version_tag_mutations.py +11 -8
  106. phoenix/server/api/mutations/span_annotations_mutations.py +15 -10
  107. phoenix/server/api/mutations/trace_annotations_mutations.py +13 -8
  108. phoenix/server/api/mutations/trace_mutations.py +3 -3
  109. phoenix/server/api/mutations/user_mutations.py +55 -26
  110. phoenix/server/api/queries.py +501 -617
  111. phoenix/server/api/routers/__init__.py +2 -2
  112. phoenix/server/api/routers/auth.py +141 -87
  113. phoenix/server/api/routers/ldap.py +229 -0
  114. phoenix/server/api/routers/oauth2.py +349 -101
  115. phoenix/server/api/routers/v1/__init__.py +22 -4
  116. phoenix/server/api/routers/v1/annotation_configs.py +19 -30
  117. phoenix/server/api/routers/v1/annotations.py +455 -13
  118. phoenix/server/api/routers/v1/datasets.py +355 -68
  119. phoenix/server/api/routers/v1/documents.py +142 -0
  120. phoenix/server/api/routers/v1/evaluations.py +20 -28
  121. phoenix/server/api/routers/v1/experiment_evaluations.py +16 -6
  122. phoenix/server/api/routers/v1/experiment_runs.py +335 -59
  123. phoenix/server/api/routers/v1/experiments.py +475 -47
  124. phoenix/server/api/routers/v1/projects.py +16 -50
  125. phoenix/server/api/routers/v1/prompts.py +50 -39
  126. phoenix/server/api/routers/v1/sessions.py +108 -0
  127. phoenix/server/api/routers/v1/spans.py +156 -96
  128. phoenix/server/api/routers/v1/traces.py +51 -77
  129. phoenix/server/api/routers/v1/users.py +64 -24
  130. phoenix/server/api/routers/v1/utils.py +3 -7
  131. phoenix/server/api/subscriptions.py +257 -93
  132. phoenix/server/api/types/Annotation.py +90 -23
  133. phoenix/server/api/types/ApiKey.py +13 -17
  134. phoenix/server/api/types/AuthMethod.py +1 -0
  135. phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +1 -0
  136. phoenix/server/api/types/Dataset.py +199 -72
  137. phoenix/server/api/types/DatasetExample.py +88 -18
  138. phoenix/server/api/types/DatasetExperimentAnnotationSummary.py +10 -0
  139. phoenix/server/api/types/DatasetLabel.py +57 -0
  140. phoenix/server/api/types/DatasetSplit.py +98 -0
  141. phoenix/server/api/types/DatasetVersion.py +49 -4
  142. phoenix/server/api/types/DocumentAnnotation.py +212 -0
  143. phoenix/server/api/types/Experiment.py +215 -68
  144. phoenix/server/api/types/ExperimentComparison.py +3 -9
  145. phoenix/server/api/types/ExperimentRepeatedRunGroup.py +155 -0
  146. phoenix/server/api/types/ExperimentRepeatedRunGroupAnnotationSummary.py +9 -0
  147. phoenix/server/api/types/ExperimentRun.py +120 -70
  148. phoenix/server/api/types/ExperimentRunAnnotation.py +158 -39
  149. phoenix/server/api/types/GenerativeModel.py +95 -42
  150. phoenix/server/api/types/GenerativeProvider.py +1 -1
  151. phoenix/server/api/types/ModelInterface.py +7 -2
  152. phoenix/server/api/types/PlaygroundModel.py +12 -2
  153. phoenix/server/api/types/Project.py +218 -185
  154. phoenix/server/api/types/ProjectSession.py +146 -29
  155. phoenix/server/api/types/ProjectSessionAnnotation.py +187 -0
  156. phoenix/server/api/types/ProjectTraceRetentionPolicy.py +1 -1
  157. phoenix/server/api/types/Prompt.py +119 -39
  158. phoenix/server/api/types/PromptLabel.py +42 -25
  159. phoenix/server/api/types/PromptVersion.py +11 -8
  160. phoenix/server/api/types/PromptVersionTag.py +65 -25
  161. phoenix/server/api/types/Span.py +130 -123
  162. phoenix/server/api/types/SpanAnnotation.py +189 -42
  163. phoenix/server/api/types/SystemApiKey.py +65 -1
  164. phoenix/server/api/types/Trace.py +184 -53
  165. phoenix/server/api/types/TraceAnnotation.py +149 -50
  166. phoenix/server/api/types/User.py +128 -33
  167. phoenix/server/api/types/UserApiKey.py +73 -26
  168. phoenix/server/api/types/node.py +10 -0
  169. phoenix/server/api/types/pagination.py +11 -2
  170. phoenix/server/app.py +154 -36
  171. phoenix/server/authorization.py +5 -4
  172. phoenix/server/bearer_auth.py +13 -5
  173. phoenix/server/cost_tracking/cost_model_lookup.py +42 -14
  174. phoenix/server/cost_tracking/model_cost_manifest.json +1085 -194
  175. phoenix/server/daemons/generative_model_store.py +61 -9
  176. phoenix/server/daemons/span_cost_calculator.py +10 -8
  177. phoenix/server/dml_event.py +13 -0
  178. phoenix/server/email/sender.py +29 -2
  179. phoenix/server/grpc_server.py +9 -9
  180. phoenix/server/jwt_store.py +8 -6
  181. phoenix/server/ldap.py +1449 -0
  182. phoenix/server/main.py +9 -3
  183. phoenix/server/oauth2.py +330 -12
  184. phoenix/server/prometheus.py +43 -6
  185. phoenix/server/rate_limiters.py +4 -9
  186. phoenix/server/retention.py +33 -20
  187. phoenix/server/session_filters.py +49 -0
  188. phoenix/server/static/.vite/manifest.json +51 -53
  189. phoenix/server/static/assets/components-BreFUQQa.js +6702 -0
  190. phoenix/server/static/assets/{index-BPCwGQr8.js → index-CTQoemZv.js} +42 -35
  191. phoenix/server/static/assets/pages-DBE5iYM3.js +9524 -0
  192. phoenix/server/static/assets/vendor-BGzfc4EU.css +1 -0
  193. phoenix/server/static/assets/vendor-DCE4v-Ot.js +920 -0
  194. phoenix/server/static/assets/vendor-codemirror-D5f205eT.js +25 -0
  195. phoenix/server/static/assets/{vendor-recharts-Bw30oz1A.js → vendor-recharts-V9cwpXsm.js} +7 -7
  196. phoenix/server/static/assets/{vendor-shiki-DZajAPeq.js → vendor-shiki-Do--csgv.js} +1 -1
  197. phoenix/server/static/assets/vendor-three-CmB8bl_y.js +3840 -0
  198. phoenix/server/templates/index.html +7 -1
  199. phoenix/server/thread_server.py +1 -2
  200. phoenix/server/utils.py +74 -0
  201. phoenix/session/client.py +55 -1
  202. phoenix/session/data_extractor.py +5 -0
  203. phoenix/session/evaluation.py +8 -4
  204. phoenix/session/session.py +44 -8
  205. phoenix/settings.py +2 -0
  206. phoenix/trace/attributes.py +80 -13
  207. phoenix/trace/dsl/query.py +2 -0
  208. phoenix/trace/projects.py +5 -0
  209. phoenix/utilities/template_formatters.py +1 -1
  210. phoenix/version.py +1 -1
  211. phoenix/server/api/types/Evaluation.py +0 -39
  212. phoenix/server/static/assets/components-D0DWAf0l.js +0 -5650
  213. phoenix/server/static/assets/pages-Creyamao.js +0 -8612
  214. phoenix/server/static/assets/vendor-CU36oj8y.js +0 -905
  215. phoenix/server/static/assets/vendor-CqDb5u4o.css +0 -1
  216. phoenix/server/static/assets/vendor-arizeai-Ctgw0e1G.js +0 -168
  217. phoenix/server/static/assets/vendor-codemirror-Cojjzqb9.js +0 -25
  218. phoenix/server/static/assets/vendor-three-BLWp5bic.js +0 -2998
  219. phoenix/utilities/deprecation.py +0 -31
  220. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/entry_points.txt +0 -0
  221. {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/licenses/LICENSE +0 -0
phoenix/db/pg_config.py CHANGED
@@ -10,12 +10,14 @@ from typing_extensions import assert_never
10
10
  def get_pg_config(
11
11
  url: URL,
12
12
  driver: Literal["psycopg", "asyncpg"],
13
+ enforce_ssl: bool = False,
13
14
  ) -> tuple[URL, dict[str, Any]]:
14
15
  """Convert SQLAlchemy URL to driver-specific configuration.
15
16
 
16
17
  Args:
17
18
  url: SQLAlchemy URL
18
19
  driver: "psycopg" or "asyncpg"
20
+ enforce_ssl: If True, ensure SSL is enabled (required for AWS RDS IAM auth)
19
21
 
20
22
  Returns:
21
23
  Tuple of (base_url, connect_args):
@@ -26,6 +28,14 @@ def get_pg_config(
26
28
  query = url.query
27
29
  ssl_args = _get_ssl_args(query)
28
30
 
31
+ if enforce_ssl and not ssl_args:
32
+ ssl_args = {"sslmode": "require"}
33
+ elif enforce_ssl and ssl_args.get("sslmode") == "disable":
34
+ raise ValueError(
35
+ "SSL cannot be disabled when using AWS RDS IAM authentication. "
36
+ "Remove 'sslmode=disable' from the connection string."
37
+ )
38
+
29
39
  # Create base URL without SSL parameters
30
40
  base_url = url.set(
31
41
  drivername=f"postgresql+{driver}",
@@ -7,6 +7,7 @@ import sqlalchemy as sa
7
7
  from pydantic import AfterValidator, BaseModel, Field, RootModel
8
8
  from sqlalchemy import func
9
9
  from sqlalchemy.ext.asyncio import AsyncSession
10
+ from sqlalchemy.sql.roles import InElementRole
10
11
 
11
12
  from phoenix.utilities import hour_of_week
12
13
 
@@ -28,7 +29,7 @@ class _MaxCount(BaseModel):
28
29
 
29
30
  def max_count_filter(
30
31
  self,
31
- project_rowids: Union[Iterable[int], sa.ScalarSelect[int]],
32
+ project_rowids: Union[Iterable[int], InElementRole],
32
33
  ) -> sa.ColumnElement[bool]:
33
34
  if self.max_count <= 0:
34
35
  return sa.literal(False)
@@ -56,7 +57,7 @@ class MaxDaysRule(_MaxDays, BaseModel):
56
57
  async def delete_traces(
57
58
  self,
58
59
  session: AsyncSession,
59
- project_rowids: Union[Iterable[int], sa.ScalarSelect[int]],
60
+ project_rowids: Union[Iterable[int], InElementRole],
60
61
  ) -> set[int]:
61
62
  if self.max_days <= 0:
62
63
  return set()
@@ -80,7 +81,7 @@ class MaxCountRule(_MaxCount, BaseModel):
80
81
  async def delete_traces(
81
82
  self,
82
83
  session: AsyncSession,
83
- project_rowids: Union[Iterable[int], sa.ScalarSelect[int]],
84
+ project_rowids: Union[Iterable[int], InElementRole],
84
85
  ) -> set[int]:
85
86
  if self.max_count <= 0:
86
87
  return set()
@@ -104,7 +105,7 @@ class MaxDaysOrCountRule(_MaxDays, _MaxCount, BaseModel):
104
105
  async def delete_traces(
105
106
  self,
106
107
  session: AsyncSession,
107
- project_rowids: Union[Iterable[int], sa.ScalarSelect[int]],
108
+ project_rowids: Union[Iterable[int], InElementRole],
108
109
  ) -> set[int]:
109
110
  if self.max_days <= 0 and self.max_count <= 0:
110
111
  return set()
@@ -130,7 +131,7 @@ class TraceRetentionRule(RootModel[Union[MaxDaysRule, MaxCountRule, MaxDaysOrCou
130
131
  async def delete_traces(
131
132
  self,
132
133
  session: AsyncSession,
133
- project_rowids: Union[Iterable[int], sa.ScalarSelect[int]],
134
+ project_rowids: Union[Iterable[int], InElementRole],
134
135
  ) -> set[int]:
135
136
  return await self.root.delete_traces(session, project_rowids)
136
137
 
@@ -199,7 +200,7 @@ class TraceRetentionCronExpression(RootModel[str]):
199
200
 
200
201
  def _parse_field(field: str, min_val: int, max_val: int) -> set[int]:
201
202
  """
202
- Parse a cron field and return the set of matching values.
203
+ Parses a cron field and returns the set of matching values.
203
204
 
204
205
  Args:
205
206
  field (str): The cron field to parse
@@ -109,6 +109,64 @@ def _phoenix_clients() -> tuple[httpx.Client, httpx.AsyncClient]:
109
109
  )
110
110
 
111
111
 
112
+ def _get_all_experiment_runs(
113
+ client: httpx.Client,
114
+ experiment_id: str,
115
+ page_size: int = 50,
116
+ ) -> list[ExperimentRun]:
117
+ """
118
+ Fetch all experiment runs using pagination to handle large datasets.
119
+
120
+ Args:
121
+ client: The HTTP client to use for requests.
122
+ experiment_id: The ID of the experiment.
123
+ page_size: Number of runs to fetch per page. Defaults to 50.
124
+
125
+ Returns:
126
+ List of all experiment runs as ExperimentRun objects.
127
+ """
128
+ all_runs: list[dict[str, Any]] = []
129
+ cursor = None
130
+
131
+ while True:
132
+ params: dict[str, Any] = {"limit": page_size}
133
+ if cursor:
134
+ params["cursor"] = cursor
135
+
136
+ try:
137
+ response = client.get(
138
+ f"v1/experiments/{experiment_id}/runs",
139
+ params=params,
140
+ )
141
+ response.raise_for_status()
142
+ data = response.json()
143
+
144
+ runs = data["data"]
145
+ all_runs.extend(runs)
146
+
147
+ # Check if there are more pages
148
+ cursor = data.get("next_cursor")
149
+ if not cursor:
150
+ break
151
+
152
+ except HTTPStatusError as e:
153
+ if e.response.status_code == 404:
154
+ # Experiment doesn't exist - treat as empty result
155
+ break
156
+ else:
157
+ raise
158
+
159
+ # Convert dicts to ExperimentRun objects
160
+ experiment_runs: list[ExperimentRun] = []
161
+ for run in all_runs:
162
+ # Parse datetime strings
163
+ run["start_time"] = datetime.fromisoformat(run["start_time"])
164
+ run["end_time"] = datetime.fromisoformat(run["end_time"])
165
+ experiment_runs.append(ExperimentRun.from_dict(run))
166
+
167
+ return experiment_runs
168
+
169
+
112
170
  Evaluators: TypeAlias = Union[
113
171
  ExperimentEvaluator,
114
172
  Sequence[ExperimentEvaluator],
@@ -231,7 +289,7 @@ def run_experiment(
231
289
  }
232
290
  if not dry_run:
233
291
  experiment_response = sync_client.post(
234
- f"/v1/datasets/{normalized_dataset.id}/experiments",
292
+ f"v1/datasets/{normalized_dataset.id}/experiments",
235
293
  json=payload,
236
294
  )
237
295
  experiment_response.raise_for_status()
@@ -303,7 +361,7 @@ def run_experiment(
303
361
  try:
304
362
  # Try to create the run directly
305
363
  resp = sync_client.post(
306
- f"/v1/experiments/{experiment.id}/runs", json=jsonify(exp_run)
364
+ f"v1/experiments/{experiment.id}/runs", json=jsonify(exp_run)
307
365
  )
308
366
  resp.raise_for_status()
309
367
  exp_run = replace(exp_run, id=resp.json()["data"]["id"])
@@ -381,7 +439,7 @@ def run_experiment(
381
439
  try:
382
440
  # Try to create the run directly
383
441
  resp = sync_client.post(
384
- f"/v1/experiments/{experiment.id}/runs", json=jsonify(exp_run)
442
+ f"v1/experiments/{experiment.id}/runs", json=jsonify(exp_run)
385
443
  )
386
444
  resp.raise_for_status()
387
445
  exp_run = replace(exp_run, id=resp.json()["data"]["id"])
@@ -420,7 +478,7 @@ def run_experiment(
420
478
  None,
421
479
  functools.partial(
422
480
  sync_client.post,
423
- url=f"/v1/experiments/{experiment.id}/runs",
481
+ url=f"v1/experiments/{experiment.id}/runs",
424
482
  json=jsonify(exp_run),
425
483
  ),
426
484
  )
@@ -498,7 +556,7 @@ def run_experiment(
498
556
  None,
499
557
  functools.partial(
500
558
  sync_client.post,
501
- url=f"/v1/experiments/{experiment.id}/runs",
559
+ url=f"v1/experiments/{experiment.id}/runs",
502
560
  json=jsonify(exp_run),
503
561
  ),
504
562
  )
@@ -548,13 +606,7 @@ def run_experiment(
548
606
 
549
607
  # Get the final state of runs from the database
550
608
  if not dry_run:
551
- all_runs = sync_client.get(f"/v1/experiments/{experiment.id}/runs").json()["data"]
552
- task_runs = []
553
- for run in all_runs:
554
- # Parse datetime strings
555
- run["start_time"] = datetime.fromisoformat(run["start_time"])
556
- run["end_time"] = datetime.fromisoformat(run["end_time"])
557
- task_runs.append(ExperimentRun.from_dict(run))
609
+ task_runs = _get_all_experiment_runs(sync_client, experiment.id)
558
610
 
559
611
  # Check if we got all expected runs
560
612
  expected_runs = len(normalized_dataset.examples) * repetitions
@@ -613,16 +665,14 @@ def evaluate_experiment(
613
665
  else:
614
666
  dataset = Dataset.from_dict(
615
667
  sync_client.get(
616
- f"/v1/datasets/{dataset_id}/examples",
668
+ f"v1/datasets/{dataset_id}/examples",
617
669
  params={"version_id": str(dataset_version_id)},
618
670
  ).json()["data"]
619
671
  )
620
672
  if not dataset.examples:
621
673
  raise ValueError(f"Dataset has no examples: {dataset_id=}, {dataset_version_id=}")
622
- experiment_runs = {
623
- exp_run["id"]: ExperimentRun.from_dict(exp_run)
624
- for exp_run in sync_client.get(f"/v1/experiments/{experiment.id}/runs").json()["data"]
625
- }
674
+ all_runs = _get_all_experiment_runs(sync_client, experiment.id)
675
+ experiment_runs = {exp_run.id: exp_run for exp_run in all_runs}
626
676
  if not experiment_runs:
627
677
  raise ValueError("Experiment has not been run")
628
678
  params = ExperimentParameters(n_examples=len(dataset.examples))
@@ -715,7 +765,7 @@ def evaluate_experiment(
715
765
  trace_id=_str_trace_id(span.get_span_context().trace_id), # type: ignore[no-untyped-call]
716
766
  )
717
767
  if not dry_run:
718
- resp = sync_client.post("/v1/experiment_evaluations", json=jsonify(eval_run))
768
+ resp = sync_client.post("v1/experiment_evaluations", json=jsonify(eval_run))
719
769
  resp.raise_for_status()
720
770
  eval_run = replace(eval_run, id=resp.json()["data"]["id"])
721
771
  return eval_run
@@ -777,7 +827,7 @@ def evaluate_experiment(
777
827
  None,
778
828
  functools.partial(
779
829
  sync_client.post,
780
- url="/v1/experiment_evaluations",
830
+ url="v1/experiment_evaluations",
781
831
  json=jsonify(eval_run),
782
832
  ),
783
833
  )
@@ -13,11 +13,10 @@ from pandas import DataFrame, Series, Timestamp, read_parquet
13
13
  from pandas.api.types import (
14
14
  is_numeric_dtype,
15
15
  )
16
- from typing_extensions import TypeAlias
16
+ from typing_extensions import TypeAlias, deprecated
17
17
 
18
18
  from phoenix.config import GENERATED_INFERENCES_NAME_PREFIX, INFERENCES_DIR
19
19
  from phoenix.datetime_utils import normalize_timestamps
20
- from phoenix.utilities.deprecation import deprecated
21
20
 
22
21
  from . import errors as err
23
22
  from .schema import (
@@ -22,6 +22,15 @@ class IsNotReadOnly(Authorization):
22
22
  return not info.context.read_only
23
23
 
24
24
 
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
+
25
34
  class IsLocked(BasePermission):
26
35
  """
27
36
  Permission class that restricts data-modifying operations when insufficient storage.
@@ -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))
@@ -17,17 +17,25 @@ from phoenix.db import models
17
17
  from phoenix.server.api.dataloaders import (
18
18
  AnnotationConfigsByProjectDataLoader,
19
19
  AnnotationSummaryDataLoader,
20
+ AverageExperimentRepeatedRunGroupLatencyDataLoader,
20
21
  AverageExperimentRunLatencyDataLoader,
21
22
  CacheForDataLoaders,
23
+ DatasetDatasetSplitsDataLoader,
22
24
  DatasetExampleRevisionsDataLoader,
25
+ DatasetExamplesAndVersionsByExperimentRunDataLoader,
23
26
  DatasetExampleSpansDataLoader,
27
+ DatasetExampleSplitsDataLoader,
24
28
  DocumentEvaluationsDataLoader,
25
29
  DocumentEvaluationSummaryDataLoader,
26
30
  DocumentRetrievalMetricsDataLoader,
27
31
  ExperimentAnnotationSummaryDataLoader,
32
+ ExperimentDatasetSplitsDataLoader,
28
33
  ExperimentErrorRatesDataLoader,
34
+ ExperimentRepeatedRunGroupAnnotationSummariesDataLoader,
35
+ ExperimentRepeatedRunGroupsDataLoader,
29
36
  ExperimentRunAnnotations,
30
37
  ExperimentRunCountsDataLoader,
38
+ ExperimentRunsByExperimentAndExampleDataLoader,
31
39
  ExperimentSequenceNumberDataLoader,
32
40
  LastUsedTimesByGenerativeModelIdDataLoader,
33
41
  LatencyMsQuantileDataLoader,
@@ -38,6 +46,7 @@ from phoenix.server.api.dataloaders import (
38
46
  ProjectIdsByTraceRetentionPolicyIdDataLoader,
39
47
  PromptVersionSequenceNumberDataLoader,
40
48
  RecordCountDataLoader,
49
+ SessionAnnotationsBySessionDataLoader,
41
50
  SessionIODataLoader,
42
51
  SessionNumTracesDataLoader,
43
52
  SessionNumTracesWithErrorDataLoader,
@@ -52,6 +61,7 @@ from phoenix.server.api.dataloaders import (
52
61
  SpanCostDetailSummaryEntriesBySpanDataLoader,
53
62
  SpanCostDetailSummaryEntriesByTraceDataLoader,
54
63
  SpanCostSummaryByExperimentDataLoader,
64
+ SpanCostSummaryByExperimentRepeatedRunGroupDataLoader,
55
65
  SpanCostSummaryByExperimentRunDataLoader,
56
66
  SpanCostSummaryByGenerativeModelDataLoader,
57
67
  SpanCostSummaryByProjectDataLoader,
@@ -62,12 +72,15 @@ from phoenix.server.api.dataloaders import (
62
72
  SpanProjectsDataLoader,
63
73
  TableFieldsDataLoader,
64
74
  TokenCountDataLoader,
75
+ TokenPricesByModelDataLoader,
76
+ TraceAnnotationsByTraceDataLoader,
65
77
  TraceByTraceIdsDataLoader,
66
78
  TraceRetentionPolicyIdByProjectIdDataLoader,
67
79
  TraceRootSpansDataLoader,
68
80
  UserRolesDataLoader,
69
81
  UsersDataLoader,
70
82
  )
83
+ from phoenix.server.api.dataloaders.dataset_labels import DatasetLabelsDataLoader
71
84
  from phoenix.server.bearer_auth import PhoenixUser
72
85
  from phoenix.server.daemons.span_cost_calculator import SpanCostCalculator
73
86
  from phoenix.server.dml_event import DmlEvent
@@ -85,17 +98,42 @@ from phoenix.server.types import (
85
98
  class DataLoaders:
86
99
  annotation_configs_by_project: AnnotationConfigsByProjectDataLoader
87
100
  annotation_summaries: AnnotationSummaryDataLoader
101
+ average_experiment_repeated_run_group_latency: (
102
+ AverageExperimentRepeatedRunGroupLatencyDataLoader
103
+ )
88
104
  average_experiment_run_latency: AverageExperimentRunLatencyDataLoader
105
+ dataset_example_fields: TableFieldsDataLoader
89
106
  dataset_example_revisions: DatasetExampleRevisionsDataLoader
90
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
91
119
  document_evaluation_summaries: DocumentEvaluationSummaryDataLoader
92
120
  document_evaluations: DocumentEvaluationsDataLoader
93
121
  document_retrieval_metrics: DocumentRetrievalMetricsDataLoader
94
122
  experiment_annotation_summaries: ExperimentAnnotationSummaryDataLoader
123
+ experiment_dataset_splits: ExperimentDatasetSplitsDataLoader
95
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
96
131
  experiment_run_annotations: ExperimentRunAnnotations
97
132
  experiment_run_counts: ExperimentRunCountsDataLoader
133
+ experiment_run_fields: TableFieldsDataLoader
134
+ experiment_runs_by_experiment_and_example: ExperimentRunsByExperimentAndExampleDataLoader
98
135
  experiment_sequence_number: ExperimentSequenceNumberDataLoader
136
+ generative_model_fields: TableFieldsDataLoader
99
137
  last_used_times_by_generative_model_id: LastUsedTimesByGenerativeModelIdDataLoader
100
138
  latency_ms_quantile: LatencyMsQuantileDataLoader
101
139
  min_start_or_max_end_times: MinStartOrMaxEndTimeDataLoader
@@ -105,14 +143,21 @@ class DataLoaders:
105
143
  project_fields: TableFieldsDataLoader
106
144
  project_trace_retention_policy_fields: TableFieldsDataLoader
107
145
  projects_by_trace_retention_policy_id: ProjectIdsByTraceRetentionPolicyIdDataLoader
146
+ prompt_fields: TableFieldsDataLoader
147
+ prompt_label_fields: TableFieldsDataLoader
108
148
  prompt_version_sequence_number: PromptVersionSequenceNumberDataLoader
149
+ prompt_version_tag_fields: TableFieldsDataLoader
150
+ project_session_annotation_fields: TableFieldsDataLoader
151
+ project_session_fields: TableFieldsDataLoader
109
152
  record_counts: RecordCountDataLoader
153
+ session_annotations_by_session: SessionAnnotationsBySessionDataLoader
110
154
  session_first_inputs: SessionIODataLoader
111
155
  session_last_outputs: SessionIODataLoader
112
156
  session_num_traces: SessionNumTracesDataLoader
113
157
  session_num_traces_with_error: SessionNumTracesWithErrorDataLoader
114
158
  session_token_usages: SessionTokenUsagesDataLoader
115
159
  session_trace_latency_ms_quantile: SessionTraceLatencyMsQuantileDataLoader
160
+ span_annotation_fields: TableFieldsDataLoader
116
161
  span_annotations: SpanAnnotationsDataLoader
117
162
  span_by_id: SpanByIdDataLoader
118
163
  span_cost_by_span: SpanCostBySpanDataLoader
@@ -128,6 +173,9 @@ class DataLoaders:
128
173
  span_cost_details_by_span_cost: SpanCostDetailsBySpanCostDataLoader
129
174
  span_cost_fields: TableFieldsDataLoader
130
175
  span_cost_summary_by_experiment: SpanCostSummaryByExperimentDataLoader
176
+ span_cost_summary_by_experiment_repeated_run_group: (
177
+ SpanCostSummaryByExperimentRepeatedRunGroupDataLoader
178
+ )
131
179
  span_cost_summary_by_experiment_run: SpanCostSummaryByExperimentRunDataLoader
132
180
  span_cost_summary_by_generative_model: SpanCostSummaryByGenerativeModelDataLoader
133
181
  span_cost_summary_by_project: SpanCostSummaryByProjectDataLoader
@@ -138,11 +186,16 @@ class DataLoaders:
138
186
  span_fields: TableFieldsDataLoader
139
187
  span_projects: SpanProjectsDataLoader
140
188
  token_counts: TokenCountDataLoader
189
+ token_prices_by_model: TokenPricesByModelDataLoader
190
+ trace_annotation_fields: TableFieldsDataLoader
191
+ trace_annotations_by_trace: TraceAnnotationsByTraceDataLoader
141
192
  trace_by_trace_ids: TraceByTraceIdsDataLoader
142
193
  trace_fields: TableFieldsDataLoader
143
194
  trace_retention_policy_id_by_project_id: TraceRetentionPolicyIdByProjectIdDataLoader
144
195
  trace_root_spans: TraceRootSpansDataLoader
145
196
  user_roles: UserRolesDataLoader
197
+ user_api_key_fields: TableFieldsDataLoader
198
+ user_fields: TableFieldsDataLoader
146
199
  users: UsersDataLoader
147
200
 
148
201
 
@@ -217,3 +270,10 @@ class Context(BaseContext):
217
270
  @cached_property
218
271
  def user(self) -> PhoenixUser:
219
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
@@ -6,9 +6,18 @@ from phoenix.server.api.dataloaders.span_cost_detail_summary_entries_by_project_
6
6
 
7
7
  from .annotation_configs_by_project import AnnotationConfigsByProjectDataLoader
8
8
  from .annotation_summaries import AnnotationSummaryCache, AnnotationSummaryDataLoader
9
+ from .average_experiment_repeated_run_group_latency import (
10
+ AverageExperimentRepeatedRunGroupLatencyDataLoader,
11
+ )
9
12
  from .average_experiment_run_latency import AverageExperimentRunLatencyDataLoader
13
+ from .dataset_dataset_splits import DatasetDatasetSplitsDataLoader
10
14
  from .dataset_example_revisions import DatasetExampleRevisionsDataLoader
11
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
12
21
  from .document_evaluation_summaries import (
13
22
  DocumentEvaluationSummaryCache,
14
23
  DocumentEvaluationSummaryDataLoader,
@@ -16,9 +25,17 @@ from .document_evaluation_summaries import (
16
25
  from .document_evaluations import DocumentEvaluationsDataLoader
17
26
  from .document_retrieval_metrics import DocumentRetrievalMetricsDataLoader
18
27
  from .experiment_annotation_summaries import ExperimentAnnotationSummaryDataLoader
28
+ from .experiment_dataset_splits import ExperimentDatasetSplitsDataLoader
19
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
20
34
  from .experiment_run_annotations import ExperimentRunAnnotations
21
35
  from .experiment_run_counts import ExperimentRunCountsDataLoader
36
+ from .experiment_runs_by_experiment_and_example import (
37
+ ExperimentRunsByExperimentAndExampleDataLoader,
38
+ )
22
39
  from .experiment_sequence_number import ExperimentSequenceNumberDataLoader
23
40
  from .last_used_times_by_generative_model_id import LastUsedTimesByGenerativeModelIdDataLoader
24
41
  from .latency_ms_quantile import LatencyMsQuantileCache, LatencyMsQuantileDataLoader
@@ -29,6 +46,7 @@ from .project_by_name import ProjectByNameDataLoader
29
46
  from .project_ids_by_trace_retention_policy_id import ProjectIdsByTraceRetentionPolicyIdDataLoader
30
47
  from .prompt_version_sequence_number import PromptVersionSequenceNumberDataLoader
31
48
  from .record_counts import RecordCountCache, RecordCountDataLoader
49
+ from .session_annotations_by_session import SessionAnnotationsBySessionDataLoader
32
50
  from .session_io import SessionIODataLoader
33
51
  from .session_num_traces import SessionNumTracesDataLoader
34
52
  from .session_num_traces_with_error import SessionNumTracesWithErrorDataLoader
@@ -44,6 +62,9 @@ from .span_cost_detail_summary_entries_by_span import SpanCostDetailSummaryEntri
44
62
  from .span_cost_detail_summary_entries_by_trace import SpanCostDetailSummaryEntriesByTraceDataLoader
45
63
  from .span_cost_details_by_span_cost import SpanCostDetailsBySpanCostDataLoader
46
64
  from .span_cost_summary_by_experiment import SpanCostSummaryByExperimentDataLoader
65
+ from .span_cost_summary_by_experiment_repeated_run_group import (
66
+ SpanCostSummaryByExperimentRepeatedRunGroupDataLoader,
67
+ )
47
68
  from .span_cost_summary_by_experiment_run import SpanCostSummaryByExperimentRunDataLoader
48
69
  from .span_cost_summary_by_generative_model import SpanCostSummaryByGenerativeModelDataLoader
49
70
  from .span_cost_summary_by_project import SpanCostSummaryByProjectDataLoader, SpanCostSummaryCache
@@ -55,6 +76,8 @@ from .span_descendants import SpanDescendantsDataLoader
55
76
  from .span_projects import SpanProjectsDataLoader
56
77
  from .table_fields import TableFieldsDataLoader
57
78
  from .token_counts import TokenCountCache, TokenCountDataLoader
79
+ from .token_prices_by_model import TokenPricesByModelDataLoader
80
+ from .trace_annotations_by_trace import TraceAnnotationsByTraceDataLoader
58
81
  from .trace_by_trace_ids import TraceByTraceIdsDataLoader
59
82
  from .trace_retention_policy_id_by_project_id import TraceRetentionPolicyIdByProjectIdDataLoader
60
83
  from .trace_root_spans import TraceRootSpansDataLoader
@@ -64,17 +87,26 @@ from .users import UsersDataLoader
64
87
  __all__ = [
65
88
  "AnnotationConfigsByProjectDataLoader",
66
89
  "AnnotationSummaryDataLoader",
90
+ "AverageExperimentRepeatedRunGroupLatencyDataLoader",
67
91
  "AverageExperimentRunLatencyDataLoader",
68
92
  "CacheForDataLoaders",
93
+ "DatasetDatasetSplitsDataLoader",
69
94
  "DatasetExampleRevisionsDataLoader",
70
95
  "DatasetExampleSpansDataLoader",
96
+ "DatasetExamplesAndVersionsByExperimentRunDataLoader",
97
+ "DatasetExampleSplitsDataLoader",
98
+ "DatasetLabelsDataLoader",
99
+ "ExperimentDatasetSplitsDataLoader",
71
100
  "DocumentEvaluationSummaryDataLoader",
72
101
  "DocumentEvaluationsDataLoader",
73
102
  "DocumentRetrievalMetricsDataLoader",
74
103
  "ExperimentAnnotationSummaryDataLoader",
75
104
  "ExperimentErrorRatesDataLoader",
105
+ "ExperimentRepeatedRunGroupsDataLoader",
106
+ "ExperimentRepeatedRunGroupAnnotationSummariesDataLoader",
76
107
  "ExperimentRunAnnotations",
77
108
  "ExperimentRunCountsDataLoader",
109
+ "ExperimentRunsByExperimentAndExampleDataLoader",
78
110
  "ExperimentSequenceNumberDataLoader",
79
111
  "LastUsedTimesByGenerativeModelIdDataLoader",
80
112
  "LatencyMsQuantileDataLoader",
@@ -85,6 +117,7 @@ __all__ = [
85
117
  "ProjectIdsByTraceRetentionPolicyIdDataLoader",
86
118
  "PromptVersionSequenceNumberDataLoader",
87
119
  "RecordCountDataLoader",
120
+ "SessionAnnotationsBySessionDataLoader",
88
121
  "SessionIODataLoader",
89
122
  "SessionNumTracesDataLoader",
90
123
  "SessionNumTracesWithErrorDataLoader",
@@ -99,6 +132,7 @@ __all__ = [
99
132
  "SpanCostDetailSummaryEntriesByTraceDataLoader",
100
133
  "SpanCostDetailsBySpanCostDataLoader",
101
134
  "SpanCostSummaryByExperimentDataLoader",
135
+ "SpanCostSummaryByExperimentRepeatedRunGroupDataLoader",
102
136
  "SpanCostSummaryByExperimentRunDataLoader",
103
137
  "SpanCostSummaryByGenerativeModelDataLoader",
104
138
  "SpanCostSummaryByProjectDataLoader",
@@ -110,6 +144,8 @@ __all__ = [
110
144
  "SpanProjectsDataLoader",
111
145
  "TableFieldsDataLoader",
112
146
  "TokenCountDataLoader",
147
+ "TokenPricesByModelDataLoader",
148
+ "TraceAnnotationsByTraceDataLoader",
113
149
  "TraceByTraceIdsDataLoader",
114
150
  "TraceRetentionPolicyIdByProjectIdDataLoader",
115
151
  "TraceRootSpansDataLoader",