arize-phoenix 12.0.0__py3-none-any.whl → 12.3.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 (44) hide show
  1. {arize_phoenix-12.0.0.dist-info → arize_phoenix-12.3.0.dist-info}/METADATA +1 -1
  2. {arize_phoenix-12.0.0.dist-info → arize_phoenix-12.3.0.dist-info}/RECORD +43 -38
  3. phoenix/db/insertion/document_annotation.py +1 -1
  4. phoenix/db/insertion/session_annotation.py +1 -1
  5. phoenix/db/insertion/span_annotation.py +1 -1
  6. phoenix/db/insertion/trace_annotation.py +1 -1
  7. phoenix/db/insertion/types.py +0 -4
  8. phoenix/db/models.py +22 -1
  9. phoenix/server/api/auth_messages.py +46 -0
  10. phoenix/server/api/context.py +2 -0
  11. phoenix/server/api/dataloaders/__init__.py +2 -0
  12. phoenix/server/api/dataloaders/dataset_labels.py +36 -0
  13. phoenix/server/api/helpers/playground_clients.py +1 -0
  14. phoenix/server/api/mutations/__init__.py +2 -0
  15. phoenix/server/api/mutations/dataset_label_mutations.py +291 -0
  16. phoenix/server/api/mutations/dataset_split_mutations.py +38 -2
  17. phoenix/server/api/queries.py +21 -0
  18. phoenix/server/api/routers/auth.py +5 -5
  19. phoenix/server/api/routers/oauth2.py +53 -51
  20. phoenix/server/api/types/Dataset.py +8 -0
  21. phoenix/server/api/types/DatasetExample.py +7 -0
  22. phoenix/server/api/types/DatasetLabel.py +23 -0
  23. phoenix/server/api/types/Prompt.py +18 -1
  24. phoenix/server/app.py +12 -12
  25. phoenix/server/cost_tracking/model_cost_manifest.json +54 -54
  26. phoenix/server/oauth2.py +2 -4
  27. phoenix/server/static/.vite/manifest.json +39 -39
  28. phoenix/server/static/assets/{components-Dl9SUw1U.js → components-Bs8eJEpU.js} +699 -378
  29. phoenix/server/static/assets/{index-CqQS0dTo.js → index-C6WEu5UP.js} +3 -3
  30. phoenix/server/static/assets/{pages-DKSjVA_E.js → pages-D-n2pkoG.js} +1149 -1142
  31. phoenix/server/static/assets/vendor-D2eEI-6h.js +914 -0
  32. phoenix/server/static/assets/{vendor-arizeai-D-lWOwIS.js → vendor-arizeai-kfOei7nf.js} +15 -24
  33. phoenix/server/static/assets/{vendor-codemirror-BRBpy3_z.js → vendor-codemirror-1bq_t1Ec.js} +3 -3
  34. phoenix/server/static/assets/{vendor-recharts--KdSwB3m.js → vendor-recharts-DQ4xfrf4.js} +1 -1
  35. phoenix/server/static/assets/{vendor-shiki-CvRzZnIo.js → vendor-shiki-GGmcIQxA.js} +1 -1
  36. phoenix/server/templates/index.html +1 -0
  37. phoenix/server/utils.py +74 -0
  38. phoenix/session/session.py +25 -5
  39. phoenix/version.py +1 -1
  40. phoenix/server/static/assets/vendor-CtbHQYl8.js +0 -903
  41. {arize_phoenix-12.0.0.dist-info → arize_phoenix-12.3.0.dist-info}/WHEEL +0 -0
  42. {arize_phoenix-12.0.0.dist-info → arize_phoenix-12.3.0.dist-info}/entry_points.txt +0 -0
  43. {arize_phoenix-12.0.0.dist-info → arize_phoenix-12.3.0.dist-info}/licenses/IP_NOTICE +0 -0
  44. {arize_phoenix-12.0.0.dist-info → arize_phoenix-12.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -18,6 +18,7 @@ from phoenix.server.api.types.DatasetExample import DatasetExample
18
18
  from phoenix.server.api.types.DatasetExperimentAnnotationSummary import (
19
19
  DatasetExperimentAnnotationSummary,
20
20
  )
21
+ from phoenix.server.api.types.DatasetLabel import DatasetLabel, to_gql_dataset_label
21
22
  from phoenix.server.api.types.DatasetVersion import DatasetVersion
22
23
  from phoenix.server.api.types.Experiment import Experiment, to_gql_experiment
23
24
  from phoenix.server.api.types.node import from_global_id_with_expected_type
@@ -303,6 +304,13 @@ class Dataset(Node):
303
304
  async for scores_tuple in await session.stream(query)
304
305
  ]
305
306
 
307
+ @strawberry.field
308
+ async def labels(self, info: Info[Context, None]) -> list[DatasetLabel]:
309
+ return [
310
+ to_gql_dataset_label(label)
311
+ for label in await info.context.data_loaders.dataset_labels.load(self.id_attr)
312
+ ]
313
+
306
314
  @strawberry.field
307
315
  def last_updated_at(self, info: Info[Context, None]) -> Optional[datetime]:
308
316
  return info.context.last_updated_at.get(self._table, self.id_attr)
@@ -142,3 +142,10 @@ class DatasetExample(Node):
142
142
  to_gql_dataset_split(split)
143
143
  for split in await info.context.data_loaders.dataset_example_splits.load(self.id_attr)
144
144
  ]
145
+
146
+
147
+ def to_gql_dataset_example(example: models.DatasetExample) -> DatasetExample:
148
+ return DatasetExample(
149
+ id_attr=example.id,
150
+ created_at=example.created_at,
151
+ )
@@ -0,0 +1,23 @@
1
+ from typing import Optional
2
+
3
+ import strawberry
4
+ from strawberry.relay import Node, NodeID
5
+
6
+ from phoenix.db import models
7
+
8
+
9
+ @strawberry.type
10
+ class DatasetLabel(Node):
11
+ id_attr: NodeID[int]
12
+ name: str
13
+ description: Optional[str]
14
+ color: str
15
+
16
+
17
+ def to_gql_dataset_label(dataset_label: models.DatasetLabel) -> DatasetLabel:
18
+ return DatasetLabel(
19
+ id_attr=dataset_label.id,
20
+ name=dataset_label.name,
21
+ description=dataset_label.description,
22
+ color=dataset_label.color,
23
+ )
@@ -9,6 +9,7 @@ from strawberry.relay import Connection, GlobalID, Node, NodeID
9
9
  from strawberry.types import Info
10
10
 
11
11
  from phoenix.db import models
12
+ from phoenix.db.types.identifier import Identifier as IdentifierModel
12
13
  from phoenix.server.api.context import Context
13
14
  from phoenix.server.api.exceptions import NotFound
14
15
  from phoenix.server.api.types.Identifier import Identifier
@@ -37,7 +38,10 @@ class Prompt(Node):
37
38
 
38
39
  @strawberry.field
39
40
  async def version(
40
- self, info: Info[Context, None], version_id: Optional[GlobalID] = None
41
+ self,
42
+ info: Info[Context, None],
43
+ version_id: Optional[GlobalID] = None,
44
+ tag_name: Optional[Identifier] = None,
41
45
  ) -> PromptVersion:
42
46
  async with info.context.db() as session:
43
47
  if version_id:
@@ -50,6 +54,19 @@ class Prompt(Node):
50
54
  )
51
55
  if not version:
52
56
  raise NotFound(f"Prompt version not found: {version_id}")
57
+ elif tag_name:
58
+ try:
59
+ name = IdentifierModel(tag_name)
60
+ except ValueError:
61
+ raise NotFound(f"Prompt version tag not found: {tag_name}")
62
+ version = await session.scalar(
63
+ select(models.PromptVersion)
64
+ .where(models.PromptVersion.prompt_id == self.id_attr)
65
+ .join_from(models.PromptVersion, models.PromptVersionTag)
66
+ .where(models.PromptVersionTag.name == name)
67
+ )
68
+ if not version:
69
+ raise NotFound(f"This prompt has no associated versions by tag {tag_name}")
53
70
  else:
54
71
  stmt = (
55
72
  select(models.PromptVersion)
phoenix/server/app.py CHANGED
@@ -67,7 +67,6 @@ from phoenix.config import (
67
67
  get_env_gql_extension_paths,
68
68
  get_env_grpc_interceptor_paths,
69
69
  get_env_host,
70
- get_env_host_root_path,
71
70
  get_env_max_spans_queue_size,
72
71
  get_env_port,
73
72
  get_env_support_email,
@@ -82,6 +81,7 @@ from phoenix.db.facilitator import Facilitator
82
81
  from phoenix.db.helpers import SupportedSQLDialect
83
82
  from phoenix.exceptions import PhoenixMigrationError
84
83
  from phoenix.pointcloud.umap_parameters import UMAPParameters
84
+ from phoenix.server.api.auth_messages import AUTH_ERROR_MESSAGES, AuthErrorCode
85
85
  from phoenix.server.api.context import Context, DataLoaders
86
86
  from phoenix.server.api.dataloaders import (
87
87
  AnnotationConfigsByProjectDataLoader,
@@ -145,6 +145,7 @@ from phoenix.server.api.dataloaders import (
145
145
  UserRolesDataLoader,
146
146
  UsersDataLoader,
147
147
  )
148
+ from phoenix.server.api.dataloaders.dataset_labels import DatasetLabelsDataLoader
148
149
  from phoenix.server.api.routers import (
149
150
  auth_router,
150
151
  create_embeddings_router,
@@ -175,6 +176,7 @@ from phoenix.server.types import (
175
176
  LastUpdatedAt,
176
177
  TokenStore,
177
178
  )
179
+ from phoenix.server.utils import get_root_path, prepend_root_path
178
180
  from phoenix.settings import Settings
179
181
  from phoenix.trace.fixtures import (
180
182
  TracesFixture,
@@ -249,6 +251,8 @@ class AppConfig(NamedTuple):
249
251
  web_manifest_path: Path
250
252
  authentication_enabled: bool
251
253
  """ Whether authentication is enabled """
254
+ auth_error_messages: dict[AuthErrorCode, str]
255
+ """ Mapping of auth error codes to user-friendly messages """
252
256
  oauth2_idps: Sequence[OAuth2Idp]
253
257
  basic_auth_disabled: bool = False
254
258
  auto_login_idp_name: Optional[str] = None
@@ -283,9 +287,6 @@ class Static(StaticFiles):
283
287
  return {}
284
288
  raise e
285
289
 
286
- def _sanitize_basename(self, basename: str) -> str:
287
- return basename[:-1] if basename.endswith("/") else basename
288
-
289
290
  async def get_response(self, path: str, scope: Scope) -> Response:
290
291
  # Redirect to the oauth2 login page if basic auth is disabled and auto_login is enabled
291
292
  # TODO: this needs to be refactored to be cleaner
@@ -294,14 +295,10 @@ class Static(StaticFiles):
294
295
  and self._app_config.basic_auth_disabled
295
296
  and self._app_config.auto_login_idp_name
296
297
  ):
297
- request = Request(scope)
298
- url = URL(
299
- str(
300
- Path(get_env_host_root_path())
301
- / f"oauth2/{self._app_config.auto_login_idp_name}/login"
302
- )
298
+ redirect_path = prepend_root_path(
299
+ scope, f"oauth2/{self._app_config.auto_login_idp_name}/login"
303
300
  )
304
- url = url.include_query_params(**request.query_params)
301
+ url = URL(redirect_path).include_query_params(**Request(scope).query_params)
305
302
  return RedirectResponse(url=url)
306
303
  try:
307
304
  response = await super().get_response(path, scope)
@@ -318,7 +315,7 @@ class Static(StaticFiles):
318
315
  "min_dist": self._app_config.min_dist,
319
316
  "n_neighbors": self._app_config.n_neighbors,
320
317
  "n_samples": self._app_config.n_samples,
321
- "basename": self._sanitize_basename(request.scope.get("root_path", "")),
318
+ "basename": get_root_path(scope),
322
319
  "platform_version": phoenix_version,
323
320
  "request": request,
324
321
  "is_development": self._app_config.is_development,
@@ -332,6 +329,7 @@ class Static(StaticFiles):
332
329
  "support_email": self._app_config.support_email,
333
330
  "has_db_threshold": self._app_config.has_db_threshold,
334
331
  "allow_external_resources": self._app_config.allow_external_resources,
332
+ "auth_error_messages": self._app_config.auth_error_messages,
335
333
  },
336
334
  )
337
335
  except Exception as e:
@@ -718,6 +716,7 @@ def create_graphql_router(
718
716
  db
719
717
  ),
720
718
  dataset_example_splits=DatasetExampleSplitsDataLoader(db),
719
+ dataset_labels=DatasetLabelsDataLoader(db),
721
720
  document_evaluation_summaries=DocumentEvaluationSummaryDataLoader(
722
721
  db,
723
722
  cache_map=(
@@ -1151,6 +1150,7 @@ def create_app(
1151
1150
  and get_env_database_usage_insertion_blocking_threshold_percentage()
1152
1151
  ),
1153
1152
  allow_external_resources=get_env_allow_external_resources(),
1153
+ auth_error_messages=dict(AUTH_ERROR_MESSAGES) if authentication_enabled else {},
1154
1154
  ),
1155
1155
  ),
1156
1156
  name="static",
@@ -449,6 +449,60 @@
449
449
  }
450
450
  ]
451
451
  },
452
+ {
453
+ "name": "claude-sonnet-4-5",
454
+ "name_pattern": "claude-sonnet-4-5",
455
+ "source": "litellm",
456
+ "token_prices": [
457
+ {
458
+ "base_rate": 3e-6,
459
+ "is_prompt": true,
460
+ "token_type": "input"
461
+ },
462
+ {
463
+ "base_rate": 0.000015,
464
+ "is_prompt": false,
465
+ "token_type": "output"
466
+ },
467
+ {
468
+ "base_rate": 3e-7,
469
+ "is_prompt": true,
470
+ "token_type": "cache_read"
471
+ },
472
+ {
473
+ "base_rate": 3.75e-6,
474
+ "is_prompt": true,
475
+ "token_type": "cache_write"
476
+ }
477
+ ]
478
+ },
479
+ {
480
+ "name": "claude-sonnet-4-5-20250929",
481
+ "name_pattern": "claude-sonnet-4-5-20250929",
482
+ "source": "litellm",
483
+ "token_prices": [
484
+ {
485
+ "base_rate": 3e-6,
486
+ "is_prompt": true,
487
+ "token_type": "input"
488
+ },
489
+ {
490
+ "base_rate": 0.000015,
491
+ "is_prompt": false,
492
+ "token_type": "output"
493
+ },
494
+ {
495
+ "base_rate": 3e-7,
496
+ "is_prompt": true,
497
+ "token_type": "cache_read"
498
+ },
499
+ {
500
+ "base_rate": 3.75e-6,
501
+ "is_prompt": true,
502
+ "token_type": "cache_write"
503
+ }
504
+ ]
505
+ },
452
506
  {
453
507
  "name": "gemini-2.0-flash",
454
508
  "name_pattern": "gemini-2.0-flash(@[a-zA-Z0-9]+)?",
@@ -1028,60 +1082,6 @@
1028
1082
  }
1029
1083
  ]
1030
1084
  },
1031
- {
1032
- "name": "gemini-flash-latest",
1033
- "name_pattern": "gemini-flash-latest",
1034
- "source": "litellm",
1035
- "token_prices": [
1036
- {
1037
- "base_rate": 3e-7,
1038
- "is_prompt": true,
1039
- "token_type": "input"
1040
- },
1041
- {
1042
- "base_rate": 2.5e-6,
1043
- "is_prompt": false,
1044
- "token_type": "output"
1045
- },
1046
- {
1047
- "base_rate": 7.5e-8,
1048
- "is_prompt": true,
1049
- "token_type": "cache_read"
1050
- },
1051
- {
1052
- "base_rate": 1e-6,
1053
- "is_prompt": true,
1054
- "token_type": "audio"
1055
- }
1056
- ]
1057
- },
1058
- {
1059
- "name": "gemini-flash-lite-latest",
1060
- "name_pattern": "gemini-flash-lite-latest",
1061
- "source": "litellm",
1062
- "token_prices": [
1063
- {
1064
- "base_rate": 1e-7,
1065
- "is_prompt": true,
1066
- "token_type": "input"
1067
- },
1068
- {
1069
- "base_rate": 4e-7,
1070
- "is_prompt": false,
1071
- "token_type": "output"
1072
- },
1073
- {
1074
- "base_rate": 2.5e-8,
1075
- "is_prompt": true,
1076
- "token_type": "cache_read"
1077
- },
1078
- {
1079
- "base_rate": 3e-7,
1080
- "is_prompt": true,
1081
- "token_type": "audio"
1082
- }
1083
- ]
1084
- },
1085
1085
  {
1086
1086
  "name": "gpt-3.5-turbo",
1087
1087
  "name_pattern": "gpt-(35|3.5)-turbo",
phoenix/server/oauth2.py CHANGED
@@ -83,10 +83,8 @@ class OAuth2Clients:
83
83
  self._auto_login_client = client
84
84
  self._clients[config.idp_name] = client
85
85
 
86
- def get_client(self, idp_name: str) -> OAuth2Client:
87
- if (client := self._clients.get(idp_name)) is None:
88
- raise ValueError(f"unknown or unregistered OAuth2 client: {idp_name}")
89
- return client
86
+ def get_client(self, idp_name: str) -> Optional[OAuth2Client]:
87
+ return self._clients.get(idp_name)
90
88
 
91
89
  @classmethod
92
90
  def from_configs(cls, configs: Iterable[OAuth2ClientConfig]) -> "OAuth2Clients":
@@ -1,32 +1,32 @@
1
1
  {
2
- "_components-Dl9SUw1U.js": {
3
- "file": "assets/components-Dl9SUw1U.js",
2
+ "_components-Bs8eJEpU.js": {
3
+ "file": "assets/components-Bs8eJEpU.js",
4
4
  "name": "components",
5
5
  "imports": [
6
- "_vendor-CtbHQYl8.js",
7
- "_vendor-arizeai-D-lWOwIS.js",
8
- "_pages-DKSjVA_E.js",
9
- "_vendor-codemirror-BRBpy3_z.js",
6
+ "_vendor-D2eEI-6h.js",
7
+ "_pages-D-n2pkoG.js",
8
+ "_vendor-arizeai-kfOei7nf.js",
9
+ "_vendor-codemirror-1bq_t1Ec.js",
10
10
  "_vendor-three-BLWp5bic.js"
11
11
  ]
12
12
  },
13
- "_pages-DKSjVA_E.js": {
14
- "file": "assets/pages-DKSjVA_E.js",
13
+ "_pages-D-n2pkoG.js": {
14
+ "file": "assets/pages-D-n2pkoG.js",
15
15
  "name": "pages",
16
16
  "imports": [
17
- "_vendor-CtbHQYl8.js",
18
- "_vendor-arizeai-D-lWOwIS.js",
19
- "_components-Dl9SUw1U.js",
20
- "_vendor-codemirror-BRBpy3_z.js",
21
- "_vendor-recharts--KdSwB3m.js"
17
+ "_vendor-D2eEI-6h.js",
18
+ "_components-Bs8eJEpU.js",
19
+ "_vendor-arizeai-kfOei7nf.js",
20
+ "_vendor-codemirror-1bq_t1Ec.js",
21
+ "_vendor-recharts-DQ4xfrf4.js"
22
22
  ]
23
23
  },
24
24
  "_vendor-BGzfc4EU.css": {
25
25
  "file": "assets/vendor-BGzfc4EU.css",
26
26
  "src": "_vendor-BGzfc4EU.css"
27
27
  },
28
- "_vendor-CtbHQYl8.js": {
29
- "file": "assets/vendor-CtbHQYl8.js",
28
+ "_vendor-D2eEI-6h.js": {
29
+ "file": "assets/vendor-D2eEI-6h.js",
30
30
  "name": "vendor",
31
31
  "imports": [
32
32
  "_vendor-three-BLWp5bic.js"
@@ -35,39 +35,39 @@
35
35
  "assets/vendor-BGzfc4EU.css"
36
36
  ]
37
37
  },
38
- "_vendor-arizeai-D-lWOwIS.js": {
39
- "file": "assets/vendor-arizeai-D-lWOwIS.js",
38
+ "_vendor-arizeai-kfOei7nf.js": {
39
+ "file": "assets/vendor-arizeai-kfOei7nf.js",
40
40
  "name": "vendor-arizeai",
41
41
  "imports": [
42
- "_vendor-CtbHQYl8.js"
42
+ "_vendor-D2eEI-6h.js"
43
43
  ]
44
44
  },
45
- "_vendor-codemirror-BRBpy3_z.js": {
46
- "file": "assets/vendor-codemirror-BRBpy3_z.js",
45
+ "_vendor-codemirror-1bq_t1Ec.js": {
46
+ "file": "assets/vendor-codemirror-1bq_t1Ec.js",
47
47
  "name": "vendor-codemirror",
48
48
  "imports": [
49
- "_vendor-CtbHQYl8.js",
50
- "_vendor-shiki-CvRzZnIo.js"
49
+ "_vendor-D2eEI-6h.js",
50
+ "_vendor-shiki-GGmcIQxA.js"
51
51
  ],
52
52
  "dynamicImports": [
53
- "_vendor-shiki-CvRzZnIo.js",
54
- "_vendor-shiki-CvRzZnIo.js",
55
- "_vendor-shiki-CvRzZnIo.js"
53
+ "_vendor-shiki-GGmcIQxA.js",
54
+ "_vendor-shiki-GGmcIQxA.js",
55
+ "_vendor-shiki-GGmcIQxA.js"
56
56
  ]
57
57
  },
58
- "_vendor-recharts--KdSwB3m.js": {
59
- "file": "assets/vendor-recharts--KdSwB3m.js",
58
+ "_vendor-recharts-DQ4xfrf4.js": {
59
+ "file": "assets/vendor-recharts-DQ4xfrf4.js",
60
60
  "name": "vendor-recharts",
61
61
  "imports": [
62
- "_vendor-CtbHQYl8.js"
62
+ "_vendor-D2eEI-6h.js"
63
63
  ]
64
64
  },
65
- "_vendor-shiki-CvRzZnIo.js": {
66
- "file": "assets/vendor-shiki-CvRzZnIo.js",
65
+ "_vendor-shiki-GGmcIQxA.js": {
66
+ "file": "assets/vendor-shiki-GGmcIQxA.js",
67
67
  "name": "vendor-shiki",
68
68
  "isDynamicEntry": true,
69
69
  "imports": [
70
- "_vendor-CtbHQYl8.js"
70
+ "_vendor-D2eEI-6h.js"
71
71
  ]
72
72
  },
73
73
  "_vendor-three-BLWp5bic.js": {
@@ -75,19 +75,19 @@
75
75
  "name": "vendor-three"
76
76
  },
77
77
  "index.tsx": {
78
- "file": "assets/index-CqQS0dTo.js",
78
+ "file": "assets/index-C6WEu5UP.js",
79
79
  "name": "index",
80
80
  "src": "index.tsx",
81
81
  "isEntry": true,
82
82
  "imports": [
83
- "_vendor-CtbHQYl8.js",
84
- "_vendor-arizeai-D-lWOwIS.js",
85
- "_pages-DKSjVA_E.js",
86
- "_components-Dl9SUw1U.js",
83
+ "_vendor-D2eEI-6h.js",
84
+ "_vendor-arizeai-kfOei7nf.js",
85
+ "_pages-D-n2pkoG.js",
86
+ "_components-Bs8eJEpU.js",
87
87
  "_vendor-three-BLWp5bic.js",
88
- "_vendor-codemirror-BRBpy3_z.js",
89
- "_vendor-shiki-CvRzZnIo.js",
90
- "_vendor-recharts--KdSwB3m.js"
88
+ "_vendor-codemirror-1bq_t1Ec.js",
89
+ "_vendor-shiki-GGmcIQxA.js",
90
+ "_vendor-recharts-DQ4xfrf4.js"
91
91
  ]
92
92
  }
93
93
  }