arize-phoenix 8.2.2__py3-none-any.whl → 8.4.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 (33) hide show
  1. {arize_phoenix-8.2.2.dist-info → arize_phoenix-8.4.0.dist-info}/METADATA +4 -3
  2. {arize_phoenix-8.2.2.dist-info → arize_phoenix-8.4.0.dist-info}/RECORD +33 -32
  3. phoenix/config.py +32 -5
  4. phoenix/db/models.py +1 -25
  5. phoenix/server/api/context.py +6 -2
  6. phoenix/server/api/dataloaders/__init__.py +4 -2
  7. phoenix/server/api/dataloaders/num_child_spans.py +35 -0
  8. phoenix/server/api/dataloaders/{span_fields.py → table_fields.py} +21 -19
  9. phoenix/server/api/helpers/playground_clients.py +4 -0
  10. phoenix/server/api/helpers/prompts/models.py +1 -0
  11. phoenix/server/api/queries.py +80 -20
  12. phoenix/server/api/types/Experiment.py +2 -4
  13. phoenix/server/api/types/ExperimentRun.py +2 -2
  14. phoenix/server/api/types/ExperimentRunAnnotation.py +2 -2
  15. phoenix/server/api/types/Project.py +67 -38
  16. phoenix/server/api/types/ProjectSession.py +2 -2
  17. phoenix/server/api/types/Span.py +35 -2
  18. phoenix/server/api/types/Trace.py +98 -30
  19. phoenix/server/app.py +6 -2
  20. phoenix/server/static/.vite/manifest.json +40 -40
  21. phoenix/server/static/assets/{components-MeFAEc1z.js → components-BgFPI6sn.js} +166 -167
  22. phoenix/server/static/assets/{index-BSRuZ-_J.js → index-CIkk8uHr.js} +9 -9
  23. phoenix/server/static/assets/{pages-NrL4hb9q.js → pages-CmDiPH1A.js} +660 -623
  24. phoenix/server/static/assets/{vendor-Cqfydjep.js → vendor-CRRq3WgM.js} +116 -116
  25. phoenix/server/static/assets/{vendor-arizeai-WnerlUPN.js → vendor-arizeai-Dq64X_0o.js} +1 -1
  26. phoenix/server/static/assets/{vendor-codemirror-D-ZZKLFq.js → vendor-codemirror-C1oevlym.js} +1 -1
  27. phoenix/server/static/assets/{vendor-recharts-KY97ZPfK.js → vendor-recharts-CPj01S89.js} +1 -1
  28. phoenix/server/static/assets/{vendor-shiki-D5K9GnFn.js → vendor-shiki-aY7rz1pm.js} +1 -1
  29. phoenix/version.py +1 -1
  30. {arize_phoenix-8.2.2.dist-info → arize_phoenix-8.4.0.dist-info}/WHEEL +0 -0
  31. {arize_phoenix-8.2.2.dist-info → arize_phoenix-8.4.0.dist-info}/entry_points.txt +0 -0
  32. {arize_phoenix-8.2.2.dist-info → arize_phoenix-8.4.0.dist-info}/licenses/IP_NOTICE +0 -0
  33. {arize_phoenix-8.2.2.dist-info → arize_phoenix-8.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, Annotated, Optional, Union
6
6
  import strawberry
7
7
  from openinference.semconv.trace import SpanAttributes
8
8
  from sqlalchemy import desc, select
9
- from strawberry import UNSET, Private, lazy
9
+ from strawberry import ID, UNSET, Private, lazy
10
10
  from strawberry.relay import Connection, GlobalID, Node, NodeID
11
11
  from strawberry.types import Info
12
12
  from typing_extensions import TypeAlias
@@ -24,6 +24,7 @@ from phoenix.server.api.types.Span import Span
24
24
  from phoenix.server.api.types.TraceAnnotation import TraceAnnotation, to_gql_trace_annotation
25
25
 
26
26
  if TYPE_CHECKING:
27
+ from phoenix.server.api.types.Project import Project
27
28
  from phoenix.server.api.types.ProjectSession import ProjectSession
28
29
 
29
30
  ProjectRowId: TypeAlias = int
@@ -33,49 +34,127 @@ TraceRowId: TypeAlias = int
33
34
  @strawberry.type
34
35
  class Trace(Node):
35
36
  trace_rowid: NodeID[TraceRowId]
36
- project_rowid: Private[ProjectRowId]
37
- project_session_rowid: Private[Optional[int]]
38
- trace_id: str
39
- start_time: datetime
40
- end_time: datetime
37
+ db_trace: Private[models.Trace] = UNSET
38
+
39
+ def __post_init__(self) -> None:
40
+ if self.db_trace and self.trace_rowid != self.db_trace.id:
41
+ raise ValueError("Trace ID mismatch")
42
+
43
+ @strawberry.field
44
+ async def trace_id(
45
+ self,
46
+ info: Info[Context, None],
47
+ ) -> ID:
48
+ if self.db_trace:
49
+ trace_id = self.db_trace.trace_id
50
+ else:
51
+ trace_id = await info.context.data_loaders.trace_fields.load(
52
+ (self.trace_rowid, models.Trace.trace_id),
53
+ )
54
+ return ID(trace_id)
55
+
56
+ @strawberry.field
57
+ async def start_time(
58
+ self,
59
+ info: Info[Context, None],
60
+ ) -> datetime:
61
+ if self.db_trace:
62
+ start_time = self.db_trace.start_time
63
+ else:
64
+ start_time = await info.context.data_loaders.trace_fields.load(
65
+ (self.trace_rowid, models.Trace.start_time),
66
+ )
67
+ return start_time
68
+
69
+ @strawberry.field
70
+ async def end_time(
71
+ self,
72
+ info: Info[Context, None],
73
+ ) -> datetime:
74
+ if self.db_trace:
75
+ end_time = self.db_trace.end_time
76
+ else:
77
+ end_time = await info.context.data_loaders.trace_fields.load(
78
+ (self.trace_rowid, models.Trace.end_time),
79
+ )
80
+ return end_time
41
81
 
42
82
  @strawberry.field
43
83
  async def latency_ms(
44
84
  self,
45
85
  info: Info[Context, None],
46
86
  ) -> Optional[float]:
47
- async with info.context.db() as session:
48
- latency = await session.scalar(
49
- select(
50
- models.Trace.latency_ms,
51
- ).where(models.Trace.id == self.trace_rowid)
87
+ if self.db_trace:
88
+ latency_ms = self.db_trace.latency_ms
89
+ else:
90
+ latency_ms = await info.context.data_loaders.trace_fields.load(
91
+ (self.trace_rowid, models.Trace.latency_ms),
52
92
  )
53
- return latency
93
+ return latency_ms
54
94
 
55
95
  @strawberry.field
56
- async def project_id(self) -> GlobalID:
96
+ async def project(
97
+ self,
98
+ info: Info[Context, None],
99
+ ) -> Annotated["Project", strawberry.lazy(".Project")]:
100
+ if self.db_trace:
101
+ project_rowid = self.db_trace.project_rowid
102
+ else:
103
+ project_rowid = await info.context.data_loaders.trace_fields.load(
104
+ (self.trace_rowid, models.Trace.project_rowid),
105
+ )
106
+ from phoenix.server.api.types.Project import Project
107
+
108
+ return Project(project_rowid=project_rowid)
109
+
110
+ @strawberry.field
111
+ async def project_id(
112
+ self,
113
+ info: Info[Context, None],
114
+ ) -> GlobalID:
115
+ if self.db_trace:
116
+ project_rowid = self.db_trace.project_rowid
117
+ else:
118
+ project_rowid = await info.context.data_loaders.trace_fields.load(
119
+ (self.trace_rowid, models.Trace.project_rowid),
120
+ )
57
121
  from phoenix.server.api.types.Project import Project
58
122
 
59
- return GlobalID(type_name=Project.__name__, node_id=str(self.project_rowid))
123
+ return GlobalID(type_name=Project.__name__, node_id=str(project_rowid))
60
124
 
61
125
  @strawberry.field
62
- async def project_session_id(self) -> Optional[GlobalID]:
63
- if self.project_session_rowid is None:
126
+ async def project_session_id(
127
+ self,
128
+ info: Info[Context, None],
129
+ ) -> Optional[GlobalID]:
130
+ if self.db_trace:
131
+ project_session_rowid = self.db_trace.project_session_rowid
132
+ else:
133
+ project_session_rowid = await info.context.data_loaders.trace_fields.load(
134
+ (self.trace_rowid, models.Trace.project_session_rowid),
135
+ )
136
+ if project_session_rowid is None:
64
137
  return None
65
138
  from phoenix.server.api.types.ProjectSession import ProjectSession
66
139
 
67
- return GlobalID(type_name=ProjectSession.__name__, node_id=str(self.project_session_rowid))
140
+ return GlobalID(type_name=ProjectSession.__name__, node_id=str(project_session_rowid))
68
141
 
69
142
  @strawberry.field
70
143
  async def session(
71
144
  self,
72
145
  info: Info[Context, None],
73
146
  ) -> Union[Annotated["ProjectSession", lazy(".ProjectSession")], None]:
74
- if self.project_session_rowid is None:
147
+ if self.db_trace:
148
+ project_session_rowid = self.db_trace.project_session_rowid
149
+ else:
150
+ project_session_rowid = await info.context.data_loaders.trace_fields.load(
151
+ (self.trace_rowid, models.Trace.project_session_rowid),
152
+ )
153
+ if project_session_rowid is None:
75
154
  return None
76
155
  from phoenix.server.api.types.ProjectSession import to_gql_project_session
77
156
 
78
- stmt = select(models.ProjectSession).filter_by(id=self.project_session_rowid)
157
+ stmt = select(models.ProjectSession).filter_by(id=project_session_rowid)
79
158
  async with info.context.db() as session:
80
159
  project_session = await session.scalar(stmt)
81
160
  if project_session is None:
@@ -141,16 +220,5 @@ class Trace(Node):
141
220
  return [to_gql_trace_annotation(annotation) for annotation in annotations]
142
221
 
143
222
 
144
- def to_gql_trace(trace: models.Trace) -> Trace:
145
- return Trace(
146
- trace_rowid=trace.id,
147
- project_rowid=trace.project_rowid,
148
- project_session_rowid=trace.project_session_rowid,
149
- trace_id=trace.trace_id,
150
- start_time=trace.start_time,
151
- end_time=trace.end_time,
152
- )
153
-
154
-
155
223
  INPUT_VALUE = SpanAttributes.INPUT_VALUE.split(".")
156
224
  OUTPUT_VALUE = SpanAttributes.OUTPUT_VALUE.split(".")
phoenix/server/app.py CHANGED
@@ -85,6 +85,7 @@ from phoenix.server.api.dataloaders import (
85
85
  ExperimentSequenceNumberDataLoader,
86
86
  LatencyMsQuantileDataLoader,
87
87
  MinStartOrMaxEndTimeDataLoader,
88
+ NumChildSpansDataLoader,
88
89
  ProjectByNameDataLoader,
89
90
  PromptVersionSequenceNumberDataLoader,
90
91
  RecordCountDataLoader,
@@ -97,8 +98,8 @@ from phoenix.server.api.dataloaders import (
97
98
  SpanByIdDataLoader,
98
99
  SpanDatasetExamplesDataLoader,
99
100
  SpanDescendantsDataLoader,
100
- SpanFieldsDataLoader,
101
101
  SpanProjectsDataLoader,
102
+ TableFieldsDataLoader,
102
103
  TokenCountDataLoader,
103
104
  TraceByTraceIdsDataLoader,
104
105
  TraceRootSpansDataLoader,
@@ -614,6 +615,8 @@ def create_graphql_router(
614
615
  else None
615
616
  ),
616
617
  ),
618
+ num_child_spans=NumChildSpansDataLoader(db),
619
+ project_fields=TableFieldsDataLoader(db, models.Project),
617
620
  prompt_version_sequence_number=PromptVersionSequenceNumberDataLoader(db),
618
621
  record_counts=RecordCountDataLoader(
619
622
  db,
@@ -626,7 +629,7 @@ def create_graphql_router(
626
629
  session_token_usages=SessionTokenUsagesDataLoader(db),
627
630
  session_trace_latency_ms_quantile=SessionTraceLatencyMsQuantileDataLoader(db),
628
631
  span_annotations=SpanAnnotationsDataLoader(db),
629
- span_fields=SpanFieldsDataLoader(db),
632
+ span_fields=TableFieldsDataLoader(db, models.Span),
630
633
  span_by_id=SpanByIdDataLoader(db),
631
634
  span_dataset_examples=SpanDatasetExamplesDataLoader(db),
632
635
  span_descendants=SpanDescendantsDataLoader(db),
@@ -636,6 +639,7 @@ def create_graphql_router(
636
639
  cache_map=cache_for_dataloaders.token_count if cache_for_dataloaders else None,
637
640
  ),
638
641
  trace_by_trace_ids=TraceByTraceIdsDataLoader(db),
642
+ trace_fields=TableFieldsDataLoader(db, models.Trace),
639
643
  trace_root_spans=TraceRootSpansDataLoader(db),
640
644
  project_by_name=ProjectByNameDataLoader(db),
641
645
  users=UsersDataLoader(db),
@@ -1,32 +1,28 @@
1
1
  {
2
- "_components-MeFAEc1z.js": {
3
- "file": "assets/components-MeFAEc1z.js",
2
+ "_components-BgFPI6sn.js": {
3
+ "file": "assets/components-BgFPI6sn.js",
4
4
  "name": "components",
5
5
  "imports": [
6
- "_vendor-Cqfydjep.js",
7
- "_pages-NrL4hb9q.js",
8
- "_vendor-arizeai-WnerlUPN.js",
9
- "_vendor-codemirror-D-ZZKLFq.js",
6
+ "_vendor-CRRq3WgM.js",
7
+ "_pages-CmDiPH1A.js",
8
+ "_vendor-arizeai-Dq64X_0o.js",
9
+ "_vendor-codemirror-C1oevlym.js",
10
10
  "_vendor-three-C-AGeJYv.js"
11
11
  ]
12
12
  },
13
- "_pages-NrL4hb9q.js": {
14
- "file": "assets/pages-NrL4hb9q.js",
13
+ "_pages-CmDiPH1A.js": {
14
+ "file": "assets/pages-CmDiPH1A.js",
15
15
  "name": "pages",
16
16
  "imports": [
17
- "_vendor-Cqfydjep.js",
18
- "_vendor-arizeai-WnerlUPN.js",
19
- "_components-MeFAEc1z.js",
20
- "_vendor-codemirror-D-ZZKLFq.js",
21
- "_vendor-recharts-KY97ZPfK.js"
17
+ "_vendor-CRRq3WgM.js",
18
+ "_vendor-arizeai-Dq64X_0o.js",
19
+ "_components-BgFPI6sn.js",
20
+ "_vendor-codemirror-C1oevlym.js",
21
+ "_vendor-recharts-CPj01S89.js"
22
22
  ]
23
23
  },
24
- "_vendor-Cg6lcjUC.css": {
25
- "file": "assets/vendor-Cg6lcjUC.css",
26
- "src": "_vendor-Cg6lcjUC.css"
27
- },
28
- "_vendor-Cqfydjep.js": {
29
- "file": "assets/vendor-Cqfydjep.js",
24
+ "_vendor-CRRq3WgM.js": {
25
+ "file": "assets/vendor-CRRq3WgM.js",
30
26
  "name": "vendor",
31
27
  "imports": [
32
28
  "_vendor-three-C-AGeJYv.js"
@@ -35,33 +31,37 @@
35
31
  "assets/vendor-Cg6lcjUC.css"
36
32
  ]
37
33
  },
38
- "_vendor-arizeai-WnerlUPN.js": {
39
- "file": "assets/vendor-arizeai-WnerlUPN.js",
34
+ "_vendor-Cg6lcjUC.css": {
35
+ "file": "assets/vendor-Cg6lcjUC.css",
36
+ "src": "_vendor-Cg6lcjUC.css"
37
+ },
38
+ "_vendor-arizeai-Dq64X_0o.js": {
39
+ "file": "assets/vendor-arizeai-Dq64X_0o.js",
40
40
  "name": "vendor-arizeai",
41
41
  "imports": [
42
- "_vendor-Cqfydjep.js"
42
+ "_vendor-CRRq3WgM.js"
43
43
  ]
44
44
  },
45
- "_vendor-codemirror-D-ZZKLFq.js": {
46
- "file": "assets/vendor-codemirror-D-ZZKLFq.js",
45
+ "_vendor-codemirror-C1oevlym.js": {
46
+ "file": "assets/vendor-codemirror-C1oevlym.js",
47
47
  "name": "vendor-codemirror",
48
48
  "imports": [
49
- "_vendor-Cqfydjep.js",
50
- "_vendor-shiki-D5K9GnFn.js"
49
+ "_vendor-CRRq3WgM.js",
50
+ "_vendor-shiki-aY7rz1pm.js"
51
51
  ]
52
52
  },
53
- "_vendor-recharts-KY97ZPfK.js": {
54
- "file": "assets/vendor-recharts-KY97ZPfK.js",
53
+ "_vendor-recharts-CPj01S89.js": {
54
+ "file": "assets/vendor-recharts-CPj01S89.js",
55
55
  "name": "vendor-recharts",
56
56
  "imports": [
57
- "_vendor-Cqfydjep.js"
57
+ "_vendor-CRRq3WgM.js"
58
58
  ]
59
59
  },
60
- "_vendor-shiki-D5K9GnFn.js": {
61
- "file": "assets/vendor-shiki-D5K9GnFn.js",
60
+ "_vendor-shiki-aY7rz1pm.js": {
61
+ "file": "assets/vendor-shiki-aY7rz1pm.js",
62
62
  "name": "vendor-shiki",
63
63
  "imports": [
64
- "_vendor-Cqfydjep.js"
64
+ "_vendor-CRRq3WgM.js"
65
65
  ]
66
66
  },
67
67
  "_vendor-three-C-AGeJYv.js": {
@@ -69,19 +69,19 @@
69
69
  "name": "vendor-three"
70
70
  },
71
71
  "index.tsx": {
72
- "file": "assets/index-BSRuZ-_J.js",
72
+ "file": "assets/index-CIkk8uHr.js",
73
73
  "name": "index",
74
74
  "src": "index.tsx",
75
75
  "isEntry": true,
76
76
  "imports": [
77
- "_vendor-Cqfydjep.js",
78
- "_vendor-arizeai-WnerlUPN.js",
79
- "_pages-NrL4hb9q.js",
80
- "_components-MeFAEc1z.js",
77
+ "_vendor-CRRq3WgM.js",
78
+ "_vendor-arizeai-Dq64X_0o.js",
79
+ "_pages-CmDiPH1A.js",
80
+ "_components-BgFPI6sn.js",
81
81
  "_vendor-three-C-AGeJYv.js",
82
- "_vendor-codemirror-D-ZZKLFq.js",
83
- "_vendor-shiki-D5K9GnFn.js",
84
- "_vendor-recharts-KY97ZPfK.js"
82
+ "_vendor-codemirror-C1oevlym.js",
83
+ "_vendor-shiki-aY7rz1pm.js",
84
+ "_vendor-recharts-CPj01S89.js"
85
85
  ]
86
86
  }
87
87
  }