arize-phoenix 11.38.0__py3-none-any.whl → 12.2.0__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.

Potentially problematic release.


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

Files changed (84) hide show
  1. {arize_phoenix-11.38.0.dist-info → arize_phoenix-12.2.0.dist-info}/METADATA +3 -3
  2. {arize_phoenix-11.38.0.dist-info → arize_phoenix-12.2.0.dist-info}/RECORD +83 -58
  3. phoenix/config.py +1 -11
  4. phoenix/db/bulk_inserter.py +8 -0
  5. phoenix/db/facilitator.py +1 -1
  6. phoenix/db/helpers.py +202 -33
  7. phoenix/db/insertion/dataset.py +7 -0
  8. phoenix/db/insertion/document_annotation.py +1 -1
  9. phoenix/db/insertion/helpers.py +2 -2
  10. phoenix/db/insertion/session_annotation.py +176 -0
  11. phoenix/db/insertion/span_annotation.py +1 -1
  12. phoenix/db/insertion/trace_annotation.py +1 -1
  13. phoenix/db/insertion/types.py +29 -3
  14. phoenix/db/migrations/versions/01a8342c9cdf_add_user_id_on_datasets.py +40 -0
  15. phoenix/db/migrations/versions/0df286449799_add_session_annotations_table.py +105 -0
  16. phoenix/db/migrations/versions/272b66ff50f8_drop_single_indices.py +119 -0
  17. phoenix/db/migrations/versions/58228d933c91_dataset_labels.py +67 -0
  18. phoenix/db/migrations/versions/699f655af132_experiment_tags.py +57 -0
  19. phoenix/db/migrations/versions/735d3d93c33e_add_composite_indices.py +41 -0
  20. phoenix/db/migrations/versions/ab513d89518b_add_user_id_on_dataset_versions.py +40 -0
  21. phoenix/db/migrations/versions/d0690a79ea51_users_on_experiments.py +40 -0
  22. phoenix/db/migrations/versions/deb2c81c0bb2_dataset_splits.py +139 -0
  23. phoenix/db/migrations/versions/e76cbd66ffc3_add_experiments_dataset_examples.py +87 -0
  24. phoenix/db/models.py +306 -46
  25. phoenix/server/api/context.py +15 -2
  26. phoenix/server/api/dataloaders/__init__.py +8 -2
  27. phoenix/server/api/dataloaders/dataset_example_splits.py +40 -0
  28. phoenix/server/api/dataloaders/dataset_labels.py +36 -0
  29. phoenix/server/api/dataloaders/session_annotations_by_session.py +29 -0
  30. phoenix/server/api/dataloaders/table_fields.py +2 -2
  31. phoenix/server/api/dataloaders/trace_annotations_by_trace.py +27 -0
  32. phoenix/server/api/helpers/playground_clients.py +66 -35
  33. phoenix/server/api/helpers/playground_users.py +26 -0
  34. phoenix/server/api/input_types/{SpanAnnotationFilter.py → AnnotationFilter.py} +22 -14
  35. phoenix/server/api/input_types/CreateProjectSessionAnnotationInput.py +37 -0
  36. phoenix/server/api/input_types/UpdateAnnotationInput.py +34 -0
  37. phoenix/server/api/mutations/__init__.py +8 -0
  38. phoenix/server/api/mutations/chat_mutations.py +8 -3
  39. phoenix/server/api/mutations/dataset_label_mutations.py +291 -0
  40. phoenix/server/api/mutations/dataset_mutations.py +5 -0
  41. phoenix/server/api/mutations/dataset_split_mutations.py +423 -0
  42. phoenix/server/api/mutations/project_session_annotations_mutations.py +161 -0
  43. phoenix/server/api/queries.py +53 -0
  44. phoenix/server/api/routers/auth.py +5 -5
  45. phoenix/server/api/routers/oauth2.py +5 -23
  46. phoenix/server/api/routers/v1/__init__.py +2 -0
  47. phoenix/server/api/routers/v1/annotations.py +320 -0
  48. phoenix/server/api/routers/v1/datasets.py +5 -0
  49. phoenix/server/api/routers/v1/experiments.py +10 -3
  50. phoenix/server/api/routers/v1/sessions.py +111 -0
  51. phoenix/server/api/routers/v1/traces.py +1 -2
  52. phoenix/server/api/routers/v1/users.py +7 -0
  53. phoenix/server/api/subscriptions.py +5 -2
  54. phoenix/server/api/types/Dataset.py +8 -0
  55. phoenix/server/api/types/DatasetExample.py +18 -0
  56. phoenix/server/api/types/DatasetLabel.py +23 -0
  57. phoenix/server/api/types/DatasetSplit.py +32 -0
  58. phoenix/server/api/types/Experiment.py +0 -4
  59. phoenix/server/api/types/Project.py +16 -0
  60. phoenix/server/api/types/ProjectSession.py +88 -3
  61. phoenix/server/api/types/ProjectSessionAnnotation.py +68 -0
  62. phoenix/server/api/types/Prompt.py +18 -1
  63. phoenix/server/api/types/Span.py +5 -5
  64. phoenix/server/api/types/Trace.py +61 -0
  65. phoenix/server/app.py +13 -14
  66. phoenix/server/cost_tracking/model_cost_manifest.json +132 -2
  67. phoenix/server/dml_event.py +13 -0
  68. phoenix/server/static/.vite/manifest.json +39 -39
  69. phoenix/server/static/assets/{components-BQPHTBfv.js → components-BG6v0EM8.js} +705 -385
  70. phoenix/server/static/assets/{index-BL5BMgJU.js → index-CSVcULw1.js} +13 -13
  71. phoenix/server/static/assets/{pages-C0Y17J0T.js → pages-DgaM7kpM.js} +1356 -1155
  72. phoenix/server/static/assets/{vendor-BdjZxMii.js → vendor-BqTEkGQU.js} +183 -183
  73. phoenix/server/static/assets/{vendor-arizeai-CHYlS8jV.js → vendor-arizeai-DlOj0PQQ.js} +15 -24
  74. phoenix/server/static/assets/{vendor-codemirror-Di6t4HnH.js → vendor-codemirror-B2PHH5yZ.js} +3 -3
  75. phoenix/server/static/assets/{vendor-recharts-C9wCDYj3.js → vendor-recharts-CKsi4IjN.js} +1 -1
  76. phoenix/server/static/assets/{vendor-shiki-MNnmOotP.js → vendor-shiki-DN26BkKE.js} +1 -1
  77. phoenix/server/utils.py +74 -0
  78. phoenix/session/session.py +25 -5
  79. phoenix/version.py +1 -1
  80. phoenix/server/api/dataloaders/experiment_repetition_counts.py +0 -39
  81. {arize_phoenix-11.38.0.dist-info → arize_phoenix-12.2.0.dist-info}/WHEEL +0 -0
  82. {arize_phoenix-11.38.0.dist-info → arize_phoenix-12.2.0.dist-info}/entry_points.txt +0 -0
  83. {arize_phoenix-11.38.0.dist-info → arize_phoenix-12.2.0.dist-info}/licenses/IP_NOTICE +0 -0
  84. {arize_phoenix-11.38.0.dist-info → arize_phoenix-12.2.0.dist-info}/licenses/LICENSE +0 -0
phoenix/db/models.py CHANGED
@@ -20,6 +20,7 @@ from sqlalchemy import (
20
20
  Integer,
21
21
  MetaData,
22
22
  Null,
23
+ PrimaryKeyConstraint,
23
24
  String,
24
25
  TypeDecorator,
25
26
  UniqueConstraint,
@@ -154,7 +155,7 @@ def render_values_w_union(
154
155
  return compiler.process(subquery, from_linter=from_linter, **kw)
155
156
 
156
157
 
157
- UserRoleName: TypeAlias = Literal["SYSTEM", "ADMIN", "MEMBER"]
158
+ UserRoleName: TypeAlias = Literal["SYSTEM", "ADMIN", "MEMBER", "VIEWER"]
158
159
  AuthMethod: TypeAlias = Literal["LOCAL", "OAUTH2"]
159
160
 
160
161
 
@@ -442,12 +443,32 @@ class _RegexStr(TypeDecorator[re.Pattern[str]]):
442
443
  return re.compile(value)
443
444
 
444
445
 
446
+ _HEX_COLOR_PATTERN = re.compile(r"^#([0-9a-f]{6})$")
447
+
448
+
449
+ class _HexColor(TypeDecorator[str]):
450
+ # See https://docs.sqlalchemy.org/en/20/core/custom_types.html
451
+ cache_ok = True
452
+ impl = String
453
+
454
+ def process_bind_param(self, value: Optional[str], _: Dialect) -> Optional[str]:
455
+ if value is None:
456
+ return None
457
+ if not _HEX_COLOR_PATTERN.match(value):
458
+ raise ValueError(f"Expected a hex color, got {value}")
459
+ return value
460
+
461
+ def process_result_value(self, value: Optional[str], _: Dialect) -> Optional[str]:
462
+ if value is None:
463
+ return None
464
+ return value
465
+
466
+
445
467
  class ExperimentRunOutput(TypedDict, total=False):
446
468
  task_output: Any
447
469
 
448
470
 
449
471
  class Base(DeclarativeBase):
450
- id: Mapped[int] = mapped_column(primary_key=True)
451
472
  # Enforce best practices for naming constraints
452
473
  # https://alembic.sqlalchemy.org/en/latest/naming.html#integration-of-naming-conventions-into-operations-autogenerate
453
474
  metadata = MetaData(
@@ -467,7 +488,12 @@ class Base(DeclarativeBase):
467
488
  }
468
489
 
469
490
 
470
- class ProjectTraceRetentionPolicy(Base):
491
+ class HasId(Base):
492
+ __abstract__ = True
493
+ id: Mapped[int] = mapped_column(primary_key=True)
494
+
495
+
496
+ class ProjectTraceRetentionPolicy(HasId):
471
497
  __tablename__ = "project_trace_retention_policies"
472
498
  name: Mapped[str] = mapped_column(String, nullable=False)
473
499
  cron_expression: Mapped[TraceRetentionCronExpression] = mapped_column(
@@ -479,7 +505,7 @@ class ProjectTraceRetentionPolicy(Base):
479
505
  )
480
506
 
481
507
 
482
- class Project(Base):
508
+ class Project(HasId):
483
509
  __tablename__ = "projects"
484
510
  name: Mapped[str]
485
511
  description: Mapped[Optional[str]]
@@ -519,7 +545,7 @@ class Project(Base):
519
545
  )
520
546
 
521
547
 
522
- class ProjectSession(Base):
548
+ class ProjectSession(HasId):
523
549
  __tablename__ = "project_sessions"
524
550
  session_id: Mapped[str] = mapped_column(String, nullable=False, unique=True)
525
551
  project_id: Mapped[int] = mapped_column(
@@ -536,7 +562,7 @@ class ProjectSession(Base):
536
562
  )
537
563
 
538
564
 
539
- class Trace(Base):
565
+ class Trace(HasId):
540
566
  __tablename__ = "traces"
541
567
  project_rowid: Mapped[int] = mapped_column(
542
568
  ForeignKey("projects.id", ondelete="CASCADE"),
@@ -591,13 +617,13 @@ class Trace(Base):
591
617
  )
592
618
 
593
619
 
594
- class Span(Base):
620
+ class Span(HasId):
595
621
  __tablename__ = "spans"
596
622
  trace_rowid: Mapped[int] = mapped_column(
597
623
  ForeignKey("traces.id", ondelete="CASCADE"),
598
624
  index=True,
599
625
  )
600
- span_id: Mapped[str] = mapped_column(index=True)
626
+ span_id: Mapped[str]
601
627
  parent_id: Mapped[Optional[str]] = mapped_column(index=True)
602
628
  name: Mapped[str]
603
629
  span_kind: Mapped[str]
@@ -894,15 +920,15 @@ async def init_models(engine: AsyncEngine) -> None:
894
920
  )
895
921
 
896
922
 
897
- class SpanAnnotation(Base):
923
+ class SpanAnnotation(HasId):
898
924
  __tablename__ = "span_annotations"
899
925
  span_rowid: Mapped[int] = mapped_column(
900
926
  ForeignKey("spans.id", ondelete="CASCADE"),
901
927
  index=True,
902
928
  )
903
929
  name: Mapped[str]
904
- label: Mapped[Optional[str]] = mapped_column(String, index=True)
905
- score: Mapped[Optional[float]] = mapped_column(Float, index=True)
930
+ label: Mapped[Optional[str]]
931
+ score: Mapped[Optional[float]]
906
932
  explanation: Mapped[Optional[str]]
907
933
  metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
908
934
  annotator_kind: Mapped[Literal["LLM", "CODE", "HUMAN"]] = mapped_column(
@@ -934,15 +960,15 @@ class SpanAnnotation(Base):
934
960
  )
935
961
 
936
962
 
937
- class TraceAnnotation(Base):
963
+ class TraceAnnotation(HasId):
938
964
  __tablename__ = "trace_annotations"
939
965
  trace_rowid: Mapped[int] = mapped_column(
940
966
  ForeignKey("traces.id", ondelete="CASCADE"),
941
967
  index=True,
942
968
  )
943
969
  name: Mapped[str]
944
- label: Mapped[Optional[str]] = mapped_column(String, index=True)
945
- score: Mapped[Optional[float]] = mapped_column(Float, index=True)
970
+ label: Mapped[Optional[str]]
971
+ score: Mapped[Optional[float]]
946
972
  explanation: Mapped[Optional[str]]
947
973
  metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
948
974
  annotator_kind: Mapped[Literal["LLM", "CODE", "HUMAN"]] = mapped_column(
@@ -971,7 +997,7 @@ class TraceAnnotation(Base):
971
997
  )
972
998
 
973
999
 
974
- class DocumentAnnotation(Base):
1000
+ class DocumentAnnotation(HasId):
975
1001
  __tablename__ = "document_annotations"
976
1002
  span_rowid: Mapped[int] = mapped_column(
977
1003
  ForeignKey("spans.id", ondelete="CASCADE"),
@@ -979,8 +1005,8 @@ class DocumentAnnotation(Base):
979
1005
  )
980
1006
  document_position: Mapped[int]
981
1007
  name: Mapped[str]
982
- label: Mapped[Optional[str]] = mapped_column(String, index=True)
983
- score: Mapped[Optional[float]] = mapped_column(Float, index=True)
1008
+ label: Mapped[Optional[str]]
1009
+ score: Mapped[Optional[float]]
984
1010
  explanation: Mapped[Optional[str]]
985
1011
  metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
986
1012
  annotator_kind: Mapped[Literal["LLM", "CODE", "HUMAN"]] = mapped_column(
@@ -1012,7 +1038,44 @@ class DocumentAnnotation(Base):
1012
1038
  )
1013
1039
 
1014
1040
 
1015
- class Dataset(Base):
1041
+ class ProjectSessionAnnotation(HasId):
1042
+ __tablename__ = "project_session_annotations"
1043
+ project_session_id: Mapped[int] = mapped_column(
1044
+ ForeignKey("project_sessions.id", ondelete="CASCADE"),
1045
+ index=True,
1046
+ )
1047
+ name: Mapped[str]
1048
+ label: Mapped[Optional[str]]
1049
+ score: Mapped[Optional[float]]
1050
+ explanation: Mapped[Optional[str]]
1051
+ metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
1052
+ annotator_kind: Mapped[Literal["LLM", "CODE", "HUMAN"]] = mapped_column(
1053
+ CheckConstraint("annotator_kind IN ('LLM', 'CODE', 'HUMAN')", name="valid_annotator_kind"),
1054
+ )
1055
+ created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
1056
+ updated_at: Mapped[datetime] = mapped_column(
1057
+ UtcTimeStamp, server_default=func.now(), onupdate=func.now()
1058
+ )
1059
+ identifier: Mapped[str] = mapped_column(
1060
+ String,
1061
+ server_default="",
1062
+ nullable=False,
1063
+ )
1064
+ source: Mapped[Literal["API", "APP"]] = mapped_column(
1065
+ CheckConstraint("source IN ('API', 'APP')", name="valid_source"),
1066
+ )
1067
+ user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"))
1068
+
1069
+ __table_args__ = (
1070
+ UniqueConstraint(
1071
+ "name",
1072
+ "project_session_id",
1073
+ "identifier",
1074
+ ),
1075
+ )
1076
+
1077
+
1078
+ class Dataset(HasId):
1016
1079
  __tablename__ = "datasets"
1017
1080
  name: Mapped[str] = mapped_column(unique=True)
1018
1081
  description: Mapped[Optional[str]]
@@ -1021,6 +1084,14 @@ class Dataset(Base):
1021
1084
  updated_at: Mapped[datetime] = mapped_column(
1022
1085
  UtcTimeStamp, server_default=func.now(), onupdate=func.now()
1023
1086
  )
1087
+ user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"))
1088
+ user: Mapped[Optional["User"]] = relationship("User")
1089
+ experiment_tags: Mapped[list["ExperimentTag"]] = relationship(
1090
+ "ExperimentTag", back_populates="dataset"
1091
+ )
1092
+ datasets_dataset_labels: Mapped[list["DatasetsDatasetLabel"]] = relationship(
1093
+ "DatasetsDatasetLabel", back_populates="dataset"
1094
+ )
1024
1095
 
1025
1096
  @hybrid_property
1026
1097
  def example_count(self) -> Optional[int]:
@@ -1071,7 +1142,45 @@ class Dataset(Base):
1071
1142
  )
1072
1143
 
1073
1144
 
1074
- class DatasetVersion(Base):
1145
+ class DatasetLabel(HasId):
1146
+ __tablename__ = "dataset_labels"
1147
+ name: Mapped[str] = mapped_column(unique=True)
1148
+ description: Mapped[Optional[str]]
1149
+ color: Mapped[str] = mapped_column(_HexColor, nullable=False)
1150
+ datasets_dataset_labels: Mapped[list["DatasetsDatasetLabel"]] = relationship(
1151
+ "DatasetsDatasetLabel", back_populates="dataset_label"
1152
+ )
1153
+ user_id: Mapped[Optional[int]] = mapped_column(
1154
+ ForeignKey("users.id", ondelete="SET NULL"),
1155
+ nullable=True,
1156
+ )
1157
+ user: Mapped[Optional["User"]] = relationship("User")
1158
+
1159
+
1160
+ class DatasetsDatasetLabel(Base):
1161
+ __tablename__ = "datasets_dataset_labels"
1162
+ dataset_id: Mapped[int] = mapped_column(
1163
+ ForeignKey("datasets.id", ondelete="CASCADE"),
1164
+ )
1165
+ dataset_label_id: Mapped[int] = mapped_column(
1166
+ ForeignKey("dataset_labels.id", ondelete="CASCADE"),
1167
+ # index on the second element of the composite primary key
1168
+ index=True,
1169
+ )
1170
+ dataset: Mapped["Dataset"] = relationship("Dataset", back_populates="datasets_dataset_labels")
1171
+ dataset_label: Mapped["DatasetLabel"] = relationship(
1172
+ "DatasetLabel", back_populates="datasets_dataset_labels"
1173
+ )
1174
+
1175
+ __table_args__ = (
1176
+ PrimaryKeyConstraint(
1177
+ "dataset_id",
1178
+ "dataset_label_id",
1179
+ ),
1180
+ )
1181
+
1182
+
1183
+ class DatasetVersion(HasId):
1075
1184
  __tablename__ = "dataset_versions"
1076
1185
  dataset_id: Mapped[int] = mapped_column(
1077
1186
  ForeignKey("datasets.id", ondelete="CASCADE"),
@@ -1080,9 +1189,11 @@ class DatasetVersion(Base):
1080
1189
  description: Mapped[Optional[str]]
1081
1190
  metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
1082
1191
  created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
1192
+ user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"))
1193
+ user: Mapped[Optional["User"]] = relationship("User")
1083
1194
 
1084
1195
 
1085
- class DatasetExample(Base):
1196
+ class DatasetExample(HasId):
1086
1197
  __tablename__ = "dataset_examples"
1087
1198
  dataset_id: Mapped[int] = mapped_column(
1088
1199
  ForeignKey("datasets.id", ondelete="CASCADE"),
@@ -1096,13 +1207,20 @@ class DatasetExample(Base):
1096
1207
  created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
1097
1208
 
1098
1209
  span: Mapped[Optional[Span]] = relationship(back_populates="dataset_examples")
1210
+ dataset_splits_dataset_examples: Mapped[list["DatasetSplitDatasetExample"]] = relationship(
1211
+ "DatasetSplitDatasetExample",
1212
+ back_populates="dataset_example",
1213
+ )
1214
+ experiment_dataset_examples: Mapped[list["ExperimentDatasetExample"]] = relationship(
1215
+ "ExperimentDatasetExample",
1216
+ back_populates="dataset_example",
1217
+ )
1099
1218
 
1100
1219
 
1101
- class DatasetExampleRevision(Base):
1220
+ class DatasetExampleRevision(HasId):
1102
1221
  __tablename__ = "dataset_example_revisions"
1103
1222
  dataset_example_id: Mapped[int] = mapped_column(
1104
1223
  ForeignKey("dataset_examples.id", ondelete="CASCADE"),
1105
- index=True,
1106
1224
  )
1107
1225
  dataset_version_id: Mapped[int] = mapped_column(
1108
1226
  ForeignKey("dataset_versions.id", ondelete="CASCADE"),
@@ -1118,6 +1236,11 @@ class DatasetExampleRevision(Base):
1118
1236
  )
1119
1237
  created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
1120
1238
 
1239
+ experiment_dataset_examples: Mapped[list["ExperimentDatasetExample"]] = relationship(
1240
+ "ExperimentDatasetExample",
1241
+ back_populates="dataset_example_revision",
1242
+ )
1243
+
1121
1244
  __table_args__ = (
1122
1245
  UniqueConstraint(
1123
1246
  "dataset_example_id",
@@ -1126,7 +1249,56 @@ class DatasetExampleRevision(Base):
1126
1249
  )
1127
1250
 
1128
1251
 
1129
- class Experiment(Base):
1252
+ class DatasetSplit(HasId):
1253
+ __tablename__ = "dataset_splits"
1254
+
1255
+ user_id: Mapped[Optional[int]] = mapped_column(
1256
+ ForeignKey("users.id", ondelete="SET NULL"),
1257
+ nullable=True,
1258
+ index=True,
1259
+ )
1260
+ name: Mapped[str] = mapped_column(String, nullable=False, unique=True)
1261
+ description: Mapped[Optional[str]]
1262
+ color: Mapped[str] = mapped_column(String, nullable=False)
1263
+ metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
1264
+ created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
1265
+ updated_at: Mapped[datetime] = mapped_column(
1266
+ UtcTimeStamp, server_default=func.now(), onupdate=func.now()
1267
+ )
1268
+ dataset_splits_dataset_examples: Mapped[list["DatasetSplitDatasetExample"]] = relationship(
1269
+ "DatasetSplitDatasetExample",
1270
+ back_populates="dataset_split",
1271
+ )
1272
+ experiment_dataset_splits: Mapped[list["ExperimentDatasetSplit"]] = relationship(
1273
+ "ExperimentDatasetSplit",
1274
+ back_populates="dataset_split",
1275
+ )
1276
+
1277
+
1278
+ class DatasetSplitDatasetExample(Base):
1279
+ __tablename__ = "dataset_splits_dataset_examples"
1280
+ dataset_split_id: Mapped[int] = mapped_column(
1281
+ ForeignKey("dataset_splits.id", ondelete="CASCADE"),
1282
+ )
1283
+ dataset_example_id: Mapped[int] = mapped_column(
1284
+ ForeignKey("dataset_examples.id", ondelete="CASCADE"),
1285
+ index=True,
1286
+ )
1287
+ dataset_split: Mapped["DatasetSplit"] = relationship(
1288
+ "DatasetSplit", back_populates="dataset_splits_dataset_examples"
1289
+ )
1290
+ dataset_example: Mapped["DatasetExample"] = relationship(
1291
+ "DatasetExample", back_populates="dataset_splits_dataset_examples"
1292
+ )
1293
+ __table_args__ = (
1294
+ PrimaryKeyConstraint(
1295
+ "dataset_split_id",
1296
+ "dataset_example_id",
1297
+ ),
1298
+ )
1299
+
1300
+
1301
+ class Experiment(HasId):
1130
1302
  __tablename__ = "experiments"
1131
1303
  dataset_id: Mapped[int] = mapped_column(
1132
1304
  ForeignKey("datasets.id", ondelete="CASCADE"),
@@ -1141,18 +1313,83 @@ class Experiment(Base):
1141
1313
  repetitions: Mapped[int]
1142
1314
  metadata_: Mapped[dict[str, Any]] = mapped_column("metadata")
1143
1315
  project_name: Mapped[Optional[str]] = mapped_column(index=True)
1316
+ user_id: Mapped[Optional[int]] = mapped_column(ForeignKey("users.id", ondelete="SET NULL"))
1144
1317
  created_at: Mapped[datetime] = mapped_column(UtcTimeStamp, server_default=func.now())
1145
1318
  updated_at: Mapped[datetime] = mapped_column(
1146
1319
  UtcTimeStamp, server_default=func.now(), onupdate=func.now()
1147
1320
  )
1321
+ user: Mapped[Optional["User"]] = relationship("User")
1322
+ experiment_dataset_splits: Mapped[list["ExperimentDatasetSplit"]] = relationship(
1323
+ "ExperimentDatasetSplit",
1324
+ back_populates="experiment",
1325
+ )
1326
+ experiment_dataset_examples: Mapped[list["ExperimentDatasetExample"]] = relationship(
1327
+ "ExperimentDatasetExample",
1328
+ back_populates="experiment",
1329
+ )
1330
+ experiment_tags: Mapped[list["ExperimentTag"]] = relationship(
1331
+ "ExperimentTag", back_populates="experiment"
1332
+ )
1148
1333
 
1149
1334
 
1150
- class ExperimentRun(Base):
1151
- __tablename__ = "experiment_runs"
1335
+ class ExperimentDatasetSplit(Base):
1336
+ __tablename__ = "experiments_dataset_splits"
1337
+ experiment_id: Mapped[int] = mapped_column(
1338
+ ForeignKey("experiments.id", ondelete="CASCADE"),
1339
+ )
1340
+ dataset_split_id: Mapped[int] = mapped_column(
1341
+ ForeignKey("dataset_splits.id", ondelete="CASCADE"),
1342
+ index=True,
1343
+ )
1344
+ experiment: Mapped["Experiment"] = relationship(
1345
+ "Experiment", back_populates="experiment_dataset_splits"
1346
+ )
1347
+ dataset_split: Mapped["DatasetSplit"] = relationship(
1348
+ "DatasetSplit", back_populates="experiment_dataset_splits"
1349
+ )
1350
+ __table_args__ = (
1351
+ PrimaryKeyConstraint(
1352
+ "experiment_id",
1353
+ "dataset_split_id",
1354
+ ),
1355
+ )
1356
+
1357
+
1358
+ class ExperimentDatasetExample(Base):
1359
+ __tablename__ = "experiments_dataset_examples"
1152
1360
  experiment_id: Mapped[int] = mapped_column(
1153
1361
  ForeignKey("experiments.id", ondelete="CASCADE"),
1362
+ )
1363
+ dataset_example_id: Mapped[int] = mapped_column(
1364
+ ForeignKey("dataset_examples.id", ondelete="CASCADE"),
1154
1365
  index=True,
1155
1366
  )
1367
+ dataset_example_revision_id: Mapped[int] = mapped_column(
1368
+ ForeignKey("dataset_example_revisions.id", ondelete="CASCADE"),
1369
+ index=True,
1370
+ )
1371
+ experiment: Mapped["Experiment"] = relationship(
1372
+ "Experiment", back_populates="experiment_dataset_examples"
1373
+ )
1374
+ dataset_example: Mapped["DatasetExample"] = relationship(
1375
+ "DatasetExample", back_populates="experiment_dataset_examples"
1376
+ )
1377
+ dataset_example_revision: Mapped["DatasetExampleRevision"] = relationship(
1378
+ "DatasetExampleRevision", back_populates="experiment_dataset_examples"
1379
+ )
1380
+ __table_args__ = (
1381
+ PrimaryKeyConstraint(
1382
+ "experiment_id",
1383
+ "dataset_example_id",
1384
+ ),
1385
+ )
1386
+
1387
+
1388
+ class ExperimentRun(HasId):
1389
+ __tablename__ = "experiment_runs"
1390
+ experiment_id: Mapped[int] = mapped_column(
1391
+ ForeignKey("experiments.id", ondelete="CASCADE"),
1392
+ )
1156
1393
  dataset_example_id: Mapped[int] = mapped_column(
1157
1394
  ForeignKey("dataset_examples.id", ondelete="CASCADE"),
1158
1395
  index=True,
@@ -1192,11 +1429,10 @@ class ExperimentRun(Base):
1192
1429
  )
1193
1430
 
1194
1431
 
1195
- class ExperimentRunAnnotation(Base):
1432
+ class ExperimentRunAnnotation(HasId):
1196
1433
  __tablename__ = "experiment_run_annotations"
1197
1434
  experiment_run_id: Mapped[int] = mapped_column(
1198
1435
  ForeignKey("experiment_runs.id", ondelete="CASCADE"),
1199
- index=True,
1200
1436
  )
1201
1437
  name: Mapped[str]
1202
1438
  annotator_kind: Mapped[str] = mapped_column(
@@ -1223,13 +1459,36 @@ class ExperimentRunAnnotation(Base):
1223
1459
  )
1224
1460
 
1225
1461
 
1226
- class UserRole(Base):
1462
+ class ExperimentTag(HasId):
1463
+ __tablename__ = "experiment_tags"
1464
+ experiment_id: Mapped[int] = mapped_column(
1465
+ ForeignKey("experiments.id", ondelete="CASCADE"),
1466
+ index=True,
1467
+ )
1468
+ dataset_id: Mapped[int] = mapped_column(
1469
+ ForeignKey("datasets.id", ondelete="CASCADE"),
1470
+ )
1471
+ user_id: Mapped[Optional[int]] = mapped_column(
1472
+ ForeignKey("users.id", ondelete="SET NULL"),
1473
+ index=True,
1474
+ nullable=True,
1475
+ )
1476
+ name: Mapped[str]
1477
+ description: Mapped[Optional[str]]
1478
+ experiment: Mapped["Experiment"] = relationship("Experiment", back_populates="experiment_tags")
1479
+ dataset: Mapped["Dataset"] = relationship("Dataset", back_populates="experiment_tags")
1480
+ user: Mapped[Optional["User"]] = relationship("User")
1481
+
1482
+ __table_args__ = (UniqueConstraint("dataset_id", "name"),)
1483
+
1484
+
1485
+ class UserRole(HasId):
1227
1486
  __tablename__ = "user_roles"
1228
1487
  name: Mapped[UserRoleName] = mapped_column(unique=True, index=True)
1229
1488
  users: Mapped[list["User"]] = relationship("User", back_populates="role")
1230
1489
 
1231
1490
 
1232
- class User(Base):
1491
+ class User(HasId):
1233
1492
  __tablename__ = "users"
1234
1493
  user_role_id: Mapped[int] = mapped_column(
1235
1494
  ForeignKey("user_roles.id", ondelete="CASCADE"),
@@ -1339,7 +1598,7 @@ class OAuth2User(User):
1339
1598
  )
1340
1599
 
1341
1600
 
1342
- class PasswordResetToken(Base):
1601
+ class PasswordResetToken(HasId):
1343
1602
  __tablename__ = "password_reset_tokens"
1344
1603
  user_id: Mapped[int] = mapped_column(
1345
1604
  ForeignKey("users.id", ondelete="CASCADE"),
@@ -1352,7 +1611,7 @@ class PasswordResetToken(Base):
1352
1611
  __table_args__ = (dict(sqlite_autoincrement=True),)
1353
1612
 
1354
1613
 
1355
- class RefreshToken(Base):
1614
+ class RefreshToken(HasId):
1356
1615
  __tablename__ = "refresh_tokens"
1357
1616
  user_id: Mapped[int] = mapped_column(
1358
1617
  ForeignKey("users.id", ondelete="CASCADE"),
@@ -1364,7 +1623,7 @@ class RefreshToken(Base):
1364
1623
  __table_args__ = (dict(sqlite_autoincrement=True),)
1365
1624
 
1366
1625
 
1367
- class AccessToken(Base):
1626
+ class AccessToken(HasId):
1368
1627
  __tablename__ = "access_tokens"
1369
1628
  user_id: Mapped[int] = mapped_column(
1370
1629
  ForeignKey("users.id", ondelete="CASCADE"),
@@ -1381,7 +1640,7 @@ class AccessToken(Base):
1381
1640
  __table_args__ = (dict(sqlite_autoincrement=True),)
1382
1641
 
1383
1642
 
1384
- class ApiKey(Base):
1643
+ class ApiKey(HasId):
1385
1644
  __tablename__ = "api_keys"
1386
1645
  user_id: Mapped[int] = mapped_column(
1387
1646
  ForeignKey("users.id", ondelete="CASCADE"),
@@ -1398,7 +1657,7 @@ class ApiKey(Base):
1398
1657
  CostType: TypeAlias = Literal["DEFAULT", "OVERRIDE"]
1399
1658
 
1400
1659
 
1401
- class GenerativeModel(Base):
1660
+ class GenerativeModel(HasId):
1402
1661
  __tablename__ = "generative_models"
1403
1662
  name: Mapped[str] = mapped_column(String, nullable=False)
1404
1663
  provider: Mapped[str]
@@ -1447,7 +1706,7 @@ class GenerativeModel(Base):
1447
1706
  )
1448
1707
 
1449
1708
 
1450
- class TokenPrice(Base):
1709
+ class TokenPrice(HasId):
1451
1710
  __tablename__ = "token_prices"
1452
1711
  model_id: Mapped[int] = mapped_column(
1453
1712
  ForeignKey("generative_models.id", ondelete="CASCADE"),
@@ -1473,7 +1732,7 @@ class TokenPrice(Base):
1473
1732
  )
1474
1733
 
1475
1734
 
1476
- class PromptLabel(Base):
1735
+ class PromptLabel(HasId):
1477
1736
  __tablename__ = "prompt_labels"
1478
1737
  name: Mapped[str] = mapped_column(String, unique=True, index=True, nullable=False)
1479
1738
  description: Mapped[Optional[str]]
@@ -1487,7 +1746,7 @@ class PromptLabel(Base):
1487
1746
  )
1488
1747
 
1489
1748
 
1490
- class Prompt(Base):
1749
+ class Prompt(HasId):
1491
1750
  __tablename__ = "prompts"
1492
1751
  source_prompt_id: Mapped[Optional[int]] = mapped_column(
1493
1752
  ForeignKey("prompts.id", ondelete="SET NULL"),
@@ -1524,7 +1783,7 @@ class Prompt(Base):
1524
1783
  )
1525
1784
 
1526
1785
 
1527
- class PromptPromptLabel(Base):
1786
+ class PromptPromptLabel(HasId):
1528
1787
  __tablename__ = "prompts_prompt_labels"
1529
1788
  prompt_label_id: Mapped[int] = mapped_column(
1530
1789
  ForeignKey("prompt_labels.id", ondelete="CASCADE"),
@@ -1545,7 +1804,7 @@ class PromptPromptLabel(Base):
1545
1804
  __table_args__ = (UniqueConstraint("prompt_label_id", "prompt_id"),)
1546
1805
 
1547
1806
 
1548
- class PromptVersion(Base):
1807
+ class PromptVersion(HasId):
1549
1808
  __tablename__ = "prompt_versions"
1550
1809
 
1551
1810
  prompt_id: Mapped[int] = mapped_column(
@@ -1594,7 +1853,7 @@ class PromptVersion(Base):
1594
1853
  )
1595
1854
 
1596
1855
 
1597
- class PromptVersionTag(Base):
1856
+ class PromptVersionTag(HasId):
1598
1857
  __tablename__ = "prompt_version_tags"
1599
1858
 
1600
1859
  name: Mapped[Identifier] = mapped_column(_Identifier, nullable=False)
@@ -1623,13 +1882,13 @@ class PromptVersionTag(Base):
1623
1882
  __table_args__ = (UniqueConstraint("name", "prompt_id"),)
1624
1883
 
1625
1884
 
1626
- class AnnotationConfig(Base):
1885
+ class AnnotationConfig(HasId):
1627
1886
  __tablename__ = "annotation_configs"
1628
1887
  name: Mapped[str] = mapped_column(String, nullable=False, unique=True)
1629
1888
  config: Mapped[AnnotationConfigType] = mapped_column(_AnnotationConfig, nullable=False)
1630
1889
 
1631
1890
 
1632
- class ProjectAnnotationConfig(Base):
1891
+ class ProjectAnnotationConfig(HasId):
1633
1892
  __tablename__ = "project_annotation_configs"
1634
1893
  project_id: Mapped[int] = mapped_column(
1635
1894
  ForeignKey("projects.id", ondelete="CASCADE"), nullable=False, index=True
@@ -1641,16 +1900,18 @@ class ProjectAnnotationConfig(Base):
1641
1900
  __table_args__ = (UniqueConstraint("project_id", "annotation_config_id"),)
1642
1901
 
1643
1902
 
1644
- class SpanCost(Base):
1903
+ class SpanCost(HasId):
1645
1904
  __tablename__ = "span_costs"
1646
1905
 
1647
1906
  span_rowid: Mapped[int] = mapped_column(
1648
1907
  ForeignKey("spans.id", ondelete="CASCADE"),
1649
1908
  nullable=False,
1909
+ index=True,
1650
1910
  )
1651
1911
  trace_rowid: Mapped[int] = mapped_column(
1652
1912
  ForeignKey("traces.id", ondelete="CASCADE"),
1653
1913
  nullable=False,
1914
+ index=True,
1654
1915
  )
1655
1916
  span_start_time: Mapped[datetime] = mapped_column(
1656
1917
  UtcTimeStamp,
@@ -1753,14 +2014,13 @@ class SpanCost(Base):
1753
2014
  self.total_tokens = (self.total_tokens or 0) + tokens
1754
2015
 
1755
2016
 
1756
- class SpanCostDetail(Base):
2017
+ class SpanCostDetail(HasId):
1757
2018
  __tablename__ = "span_cost_details"
1758
2019
  span_cost_id: Mapped[int] = mapped_column(
1759
2020
  ForeignKey("span_costs.id", ondelete="CASCADE"),
1760
2021
  nullable=False,
1761
- index=True,
1762
2022
  )
1763
- token_type: Mapped[str]
2023
+ token_type: Mapped[str] = mapped_column(index=True)
1764
2024
  is_prompt: Mapped[bool]
1765
2025
 
1766
2026
  cost: Mapped[Optional[float]]