arize-phoenix 12.8.0__py3-none-any.whl → 12.9.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.
- {arize_phoenix-12.8.0.dist-info → arize_phoenix-12.9.0.dist-info}/METADATA +3 -1
- {arize_phoenix-12.8.0.dist-info → arize_phoenix-12.9.0.dist-info}/RECORD +70 -67
- phoenix/config.py +131 -9
- phoenix/db/engines.py +127 -14
- phoenix/db/iam_auth.py +64 -0
- phoenix/db/pg_config.py +10 -0
- phoenix/server/api/context.py +23 -0
- phoenix/server/api/dataloaders/__init__.py +6 -0
- phoenix/server/api/dataloaders/experiment_repeated_run_groups.py +0 -2
- phoenix/server/api/dataloaders/experiment_runs_by_experiment_and_example.py +44 -0
- phoenix/server/api/dataloaders/span_costs.py +3 -9
- phoenix/server/api/dataloaders/token_prices_by_model.py +30 -0
- phoenix/server/api/helpers/playground_clients.py +3 -3
- phoenix/server/api/input_types/PromptVersionInput.py +47 -1
- phoenix/server/api/mutations/annotation_config_mutations.py +2 -2
- phoenix/server/api/mutations/api_key_mutations.py +2 -15
- phoenix/server/api/mutations/chat_mutations.py +3 -2
- phoenix/server/api/mutations/dataset_label_mutations.py +12 -6
- phoenix/server/api/mutations/dataset_mutations.py +8 -8
- phoenix/server/api/mutations/dataset_split_mutations.py +13 -9
- phoenix/server/api/mutations/model_mutations.py +4 -4
- phoenix/server/api/mutations/project_session_annotations_mutations.py +4 -7
- phoenix/server/api/mutations/prompt_label_mutations.py +3 -3
- phoenix/server/api/mutations/prompt_mutations.py +24 -117
- phoenix/server/api/mutations/prompt_version_tag_mutations.py +8 -5
- phoenix/server/api/mutations/span_annotations_mutations.py +10 -5
- phoenix/server/api/mutations/trace_annotations_mutations.py +9 -4
- phoenix/server/api/mutations/user_mutations.py +4 -4
- phoenix/server/api/queries.py +65 -210
- phoenix/server/api/subscriptions.py +4 -4
- phoenix/server/api/types/Annotation.py +90 -23
- phoenix/server/api/types/ApiKey.py +13 -17
- phoenix/server/api/types/Dataset.py +88 -48
- phoenix/server/api/types/DatasetExample.py +34 -30
- phoenix/server/api/types/DatasetLabel.py +47 -13
- phoenix/server/api/types/DatasetSplit.py +87 -21
- phoenix/server/api/types/DatasetVersion.py +49 -4
- phoenix/server/api/types/DocumentAnnotation.py +182 -62
- phoenix/server/api/types/Experiment.py +146 -55
- phoenix/server/api/types/ExperimentRepeatedRunGroup.py +10 -1
- phoenix/server/api/types/ExperimentRun.py +118 -61
- phoenix/server/api/types/ExperimentRunAnnotation.py +158 -39
- phoenix/server/api/types/GenerativeModel.py +95 -42
- phoenix/server/api/types/ModelInterface.py +7 -2
- phoenix/server/api/types/PlaygroundModel.py +12 -2
- phoenix/server/api/types/Project.py +70 -75
- phoenix/server/api/types/ProjectSession.py +69 -37
- phoenix/server/api/types/ProjectSessionAnnotation.py +166 -47
- phoenix/server/api/types/ProjectTraceRetentionPolicy.py +1 -1
- phoenix/server/api/types/Prompt.py +82 -44
- phoenix/server/api/types/PromptLabel.py +47 -13
- phoenix/server/api/types/PromptVersion.py +11 -8
- phoenix/server/api/types/PromptVersionTag.py +65 -25
- phoenix/server/api/types/Span.py +116 -115
- phoenix/server/api/types/SpanAnnotation.py +189 -42
- phoenix/server/api/types/SystemApiKey.py +65 -1
- phoenix/server/api/types/Trace.py +45 -44
- phoenix/server/api/types/TraceAnnotation.py +144 -48
- phoenix/server/api/types/User.py +103 -33
- phoenix/server/api/types/UserApiKey.py +73 -26
- phoenix/server/app.py +29 -0
- phoenix/server/static/.vite/manifest.json +9 -9
- phoenix/server/static/assets/{components-Bem6_7MW.js → components-v927s3NF.js} +427 -397
- phoenix/server/static/assets/{index-NdiXbuNL.js → index-DrD9eSrN.js} +9 -5
- phoenix/server/static/assets/{pages-CEJgMVKU.js → pages-GVybXa_W.js} +489 -486
- phoenix/version.py +1 -1
- {arize_phoenix-12.8.0.dist-info → arize_phoenix-12.9.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-12.8.0.dist-info → arize_phoenix-12.9.0.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-12.8.0.dist-info → arize_phoenix-12.9.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-12.8.0.dist-info → arize_phoenix-12.9.0.dist-info}/licenses/LICENSE +0 -0
phoenix/server/api/types/Span.py
CHANGED
|
@@ -34,17 +34,14 @@ from phoenix.server.api.input_types.SpanAnnotationSort import (
|
|
|
34
34
|
)
|
|
35
35
|
from phoenix.server.api.types.AnnotationSummary import AnnotationSummary
|
|
36
36
|
from phoenix.server.api.types.CostBreakdown import CostBreakdown
|
|
37
|
-
from phoenix.server.api.types.DocumentAnnotation import
|
|
38
|
-
DocumentAnnotation,
|
|
39
|
-
to_gql_document_annotation,
|
|
40
|
-
)
|
|
37
|
+
from phoenix.server.api.types.DocumentAnnotation import DocumentAnnotation
|
|
41
38
|
from phoenix.server.api.types.DocumentRetrievalMetrics import DocumentRetrievalMetrics
|
|
42
39
|
from phoenix.server.api.types.ExampleRevisionInterface import ExampleRevision
|
|
43
40
|
from phoenix.server.api.types.GenerativeProvider import GenerativeProvider
|
|
44
41
|
from phoenix.server.api.types.MimeType import MimeType
|
|
45
42
|
from phoenix.server.api.types.pagination import ConnectionArgs, CursorString, connection_from_list
|
|
46
43
|
from phoenix.server.api.types.SortDir import SortDir
|
|
47
|
-
from phoenix.server.api.types.SpanAnnotation import SpanAnnotation
|
|
44
|
+
from phoenix.server.api.types.SpanAnnotation import SpanAnnotation
|
|
48
45
|
from phoenix.server.api.types.SpanCostDetailSummaryEntry import SpanCostDetailSummaryEntry
|
|
49
46
|
from phoenix.server.api.types.SpanCostSummary import SpanCostSummary
|
|
50
47
|
from phoenix.server.api.types.SpanIOValue import SpanIOValue, truncate_value
|
|
@@ -126,11 +123,11 @@ SpanRowId: TypeAlias = int
|
|
|
126
123
|
|
|
127
124
|
@strawberry.type
|
|
128
125
|
class Span(Node):
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
id: NodeID[SpanRowId]
|
|
127
|
+
db_record: strawberry.Private[Optional[models.Span]] = None
|
|
131
128
|
|
|
132
129
|
def __post_init__(self) -> None:
|
|
133
|
-
if self.
|
|
130
|
+
if self.db_record and self.id != self.db_record.id:
|
|
134
131
|
raise ValueError("Span ID mismatch")
|
|
135
132
|
|
|
136
133
|
@strawberry.field
|
|
@@ -138,10 +135,10 @@ class Span(Node):
|
|
|
138
135
|
self,
|
|
139
136
|
info: Info[Context, None],
|
|
140
137
|
) -> str:
|
|
141
|
-
if self.
|
|
142
|
-
return self.
|
|
138
|
+
if self.db_record:
|
|
139
|
+
return self.db_record.name
|
|
143
140
|
value = await info.context.data_loaders.span_fields.load(
|
|
144
|
-
(self.
|
|
141
|
+
(self.id, models.Span.name),
|
|
145
142
|
)
|
|
146
143
|
return str(value)
|
|
147
144
|
|
|
@@ -150,11 +147,11 @@ class Span(Node):
|
|
|
150
147
|
self,
|
|
151
148
|
info: Info[Context, None],
|
|
152
149
|
) -> SpanStatusCode:
|
|
153
|
-
if self.
|
|
154
|
-
value = self.
|
|
150
|
+
if self.db_record:
|
|
151
|
+
value = self.db_record.status_code
|
|
155
152
|
else:
|
|
156
153
|
value = await info.context.data_loaders.span_fields.load(
|
|
157
|
-
(self.
|
|
154
|
+
(self.id, models.Span.status_code),
|
|
158
155
|
)
|
|
159
156
|
return SpanStatusCode(value)
|
|
160
157
|
|
|
@@ -163,10 +160,10 @@ class Span(Node):
|
|
|
163
160
|
self,
|
|
164
161
|
info: Info[Context, None],
|
|
165
162
|
) -> str:
|
|
166
|
-
if self.
|
|
167
|
-
return self.
|
|
163
|
+
if self.db_record:
|
|
164
|
+
return self.db_record.status_message
|
|
168
165
|
value = await info.context.data_loaders.span_fields.load(
|
|
169
|
-
(self.
|
|
166
|
+
(self.id, models.Span.status_message),
|
|
170
167
|
)
|
|
171
168
|
return str(value)
|
|
172
169
|
|
|
@@ -175,10 +172,10 @@ class Span(Node):
|
|
|
175
172
|
self,
|
|
176
173
|
info: Info[Context, None],
|
|
177
174
|
) -> datetime:
|
|
178
|
-
if self.
|
|
179
|
-
return self.
|
|
175
|
+
if self.db_record:
|
|
176
|
+
return self.db_record.start_time
|
|
180
177
|
value = await info.context.data_loaders.span_fields.load(
|
|
181
|
-
(self.
|
|
178
|
+
(self.id, models.Span.start_time),
|
|
182
179
|
)
|
|
183
180
|
return cast(datetime, value)
|
|
184
181
|
|
|
@@ -187,10 +184,10 @@ class Span(Node):
|
|
|
187
184
|
self,
|
|
188
185
|
info: Info[Context, None],
|
|
189
186
|
) -> Optional[datetime]:
|
|
190
|
-
if self.
|
|
191
|
-
return self.
|
|
187
|
+
if self.db_record:
|
|
188
|
+
return self.db_record.end_time
|
|
192
189
|
value = await info.context.data_loaders.span_fields.load(
|
|
193
|
-
(self.
|
|
190
|
+
(self.id, models.Span.end_time),
|
|
194
191
|
)
|
|
195
192
|
return cast(datetime, value)
|
|
196
193
|
|
|
@@ -199,10 +196,10 @@ class Span(Node):
|
|
|
199
196
|
self,
|
|
200
197
|
info: Info[Context, None],
|
|
201
198
|
) -> Optional[float]:
|
|
202
|
-
if self.
|
|
203
|
-
return self.
|
|
199
|
+
if self.db_record:
|
|
200
|
+
return self.db_record.latency_ms
|
|
204
201
|
value = await info.context.data_loaders.span_fields.load(
|
|
205
|
-
(self.
|
|
202
|
+
(self.id, models.Span.latency_ms),
|
|
206
203
|
)
|
|
207
204
|
return cast(float, value)
|
|
208
205
|
|
|
@@ -213,11 +210,11 @@ class Span(Node):
|
|
|
213
210
|
self,
|
|
214
211
|
info: Info[Context, None],
|
|
215
212
|
) -> Optional[ID]:
|
|
216
|
-
if self.
|
|
217
|
-
value = self.
|
|
213
|
+
if self.db_record:
|
|
214
|
+
value = self.db_record.parent_id
|
|
218
215
|
else:
|
|
219
216
|
value = await info.context.data_loaders.span_fields.load(
|
|
220
|
-
(self.
|
|
217
|
+
(self.id, models.Span.parent_id),
|
|
221
218
|
)
|
|
222
219
|
return None if value is None else ID(value)
|
|
223
220
|
|
|
@@ -226,11 +223,11 @@ class Span(Node):
|
|
|
226
223
|
self,
|
|
227
224
|
info: Info[Context, None],
|
|
228
225
|
) -> SpanKind:
|
|
229
|
-
if self.
|
|
230
|
-
value = self.
|
|
226
|
+
if self.db_record:
|
|
227
|
+
value = self.db_record.span_kind
|
|
231
228
|
else:
|
|
232
229
|
value = await info.context.data_loaders.span_fields.load(
|
|
233
|
-
(self.
|
|
230
|
+
(self.id, models.Span.span_kind),
|
|
234
231
|
)
|
|
235
232
|
return SpanKind(value)
|
|
236
233
|
|
|
@@ -239,11 +236,11 @@ class Span(Node):
|
|
|
239
236
|
self,
|
|
240
237
|
info: Info[Context, None],
|
|
241
238
|
) -> ID:
|
|
242
|
-
if self.
|
|
243
|
-
span_id = self.
|
|
239
|
+
if self.db_record:
|
|
240
|
+
span_id = self.db_record.span_id
|
|
244
241
|
else:
|
|
245
242
|
span_id = await info.context.data_loaders.span_fields.load(
|
|
246
|
-
(self.
|
|
243
|
+
(self.id, models.Span.span_id),
|
|
247
244
|
)
|
|
248
245
|
return ID(span_id)
|
|
249
246
|
|
|
@@ -252,31 +249,31 @@ class Span(Node):
|
|
|
252
249
|
self,
|
|
253
250
|
info: Info[Context, None],
|
|
254
251
|
) -> Annotated["Trace", strawberry.lazy(".Trace")]:
|
|
255
|
-
if self.
|
|
256
|
-
trace_rowid = self.
|
|
252
|
+
if self.db_record:
|
|
253
|
+
trace_rowid = self.db_record.trace_rowid
|
|
257
254
|
else:
|
|
258
255
|
trace_rowid = await info.context.data_loaders.span_fields.load(
|
|
259
|
-
(self.
|
|
256
|
+
(self.id, models.Span.trace_rowid),
|
|
260
257
|
)
|
|
261
258
|
from phoenix.server.api.types.Trace import Trace
|
|
262
259
|
|
|
263
|
-
return Trace(
|
|
260
|
+
return Trace(id=trace_rowid)
|
|
264
261
|
|
|
265
262
|
@strawberry.field
|
|
266
263
|
async def context(
|
|
267
264
|
self,
|
|
268
265
|
info: Info[Context, None],
|
|
269
266
|
) -> SpanContext:
|
|
270
|
-
if self.
|
|
271
|
-
trace_id = self.
|
|
272
|
-
span_id = self.
|
|
267
|
+
if self.db_record:
|
|
268
|
+
trace_id = self.db_record.trace.trace_id
|
|
269
|
+
span_id = self.db_record.span_id
|
|
273
270
|
else:
|
|
274
271
|
span_id, trace_id = await gather(
|
|
275
272
|
info.context.data_loaders.span_fields.load(
|
|
276
|
-
(self.
|
|
273
|
+
(self.id, models.Span.span_id),
|
|
277
274
|
),
|
|
278
275
|
info.context.data_loaders.span_fields.load(
|
|
279
|
-
(self.
|
|
276
|
+
(self.id, models.Trace.trace_id),
|
|
280
277
|
),
|
|
281
278
|
)
|
|
282
279
|
return SpanContext(trace_id=ID(trace_id), span_id=ID(span_id))
|
|
@@ -288,11 +285,11 @@ class Span(Node):
|
|
|
288
285
|
self,
|
|
289
286
|
info: Info[Context, None],
|
|
290
287
|
) -> str:
|
|
291
|
-
if self.
|
|
292
|
-
value = self.
|
|
288
|
+
if self.db_record:
|
|
289
|
+
value = self.db_record.attributes
|
|
293
290
|
else:
|
|
294
291
|
value = await info.context.data_loaders.span_fields.load(
|
|
295
|
-
(self.
|
|
292
|
+
(self.id, models.Span.attributes),
|
|
296
293
|
)
|
|
297
294
|
return json.dumps(_hide_embedding_vectors(value), cls=_JSONEncoder)
|
|
298
295
|
|
|
@@ -303,11 +300,11 @@ class Span(Node):
|
|
|
303
300
|
self,
|
|
304
301
|
info: Info[Context, None],
|
|
305
302
|
) -> Optional[str]:
|
|
306
|
-
if self.
|
|
307
|
-
value = self.
|
|
303
|
+
if self.db_record:
|
|
304
|
+
value = self.db_record.metadata_
|
|
308
305
|
else:
|
|
309
306
|
value = await info.context.data_loaders.span_fields.load(
|
|
310
|
-
(self.
|
|
307
|
+
(self.id, models.Span.metadata_),
|
|
311
308
|
)
|
|
312
309
|
return _convert_metadata_to_string(value)
|
|
313
310
|
|
|
@@ -316,10 +313,10 @@ class Span(Node):
|
|
|
316
313
|
self,
|
|
317
314
|
info: Info[Context, None],
|
|
318
315
|
) -> Optional[int]:
|
|
319
|
-
if self.
|
|
320
|
-
return self.
|
|
316
|
+
if self.db_record:
|
|
317
|
+
return self.db_record.num_documents
|
|
321
318
|
value = await info.context.data_loaders.span_fields.load(
|
|
322
|
-
(self.
|
|
319
|
+
(self.id, models.Span.num_documents),
|
|
323
320
|
)
|
|
324
321
|
return cast(int, value)
|
|
325
322
|
|
|
@@ -328,10 +325,10 @@ class Span(Node):
|
|
|
328
325
|
self,
|
|
329
326
|
info: Info[Context, None],
|
|
330
327
|
) -> Optional[int]:
|
|
331
|
-
if self.
|
|
332
|
-
return self.
|
|
328
|
+
if self.db_record:
|
|
329
|
+
return self.db_record.llm_token_count_total
|
|
333
330
|
value = await info.context.data_loaders.span_fields.load(
|
|
334
|
-
(self.
|
|
331
|
+
(self.id, models.Span.llm_token_count_total),
|
|
335
332
|
)
|
|
336
333
|
return cast(Optional[int], value)
|
|
337
334
|
|
|
@@ -340,10 +337,10 @@ class Span(Node):
|
|
|
340
337
|
self,
|
|
341
338
|
info: Info[Context, None],
|
|
342
339
|
) -> Optional[int]:
|
|
343
|
-
if self.
|
|
344
|
-
return self.
|
|
340
|
+
if self.db_record:
|
|
341
|
+
return self.db_record.llm_token_count_prompt
|
|
345
342
|
value = await info.context.data_loaders.span_fields.load(
|
|
346
|
-
(self.
|
|
343
|
+
(self.id, models.Span.llm_token_count_prompt),
|
|
347
344
|
)
|
|
348
345
|
return cast(Optional[int], value)
|
|
349
346
|
|
|
@@ -352,10 +349,10 @@ class Span(Node):
|
|
|
352
349
|
self,
|
|
353
350
|
info: Info[Context, None],
|
|
354
351
|
) -> Optional[int]:
|
|
355
|
-
if self.
|
|
356
|
-
return self.
|
|
352
|
+
if self.db_record:
|
|
353
|
+
return self.db_record.llm_token_count_completion
|
|
357
354
|
value = await info.context.data_loaders.span_fields.load(
|
|
358
|
-
(self.
|
|
355
|
+
(self.id, models.Span.llm_token_count_completion),
|
|
359
356
|
)
|
|
360
357
|
return cast(Optional[int], value)
|
|
361
358
|
|
|
@@ -364,11 +361,11 @@ class Span(Node):
|
|
|
364
361
|
self,
|
|
365
362
|
info: Info[Context, None],
|
|
366
363
|
) -> TokenCountPromptDetails:
|
|
367
|
-
if self.
|
|
368
|
-
attributes = self.
|
|
364
|
+
if self.db_record:
|
|
365
|
+
attributes = self.db_record.attributes
|
|
369
366
|
else:
|
|
370
367
|
attributes = await info.context.data_loaders.span_fields.load(
|
|
371
|
-
(self.
|
|
368
|
+
(self.id, models.Span.attributes),
|
|
372
369
|
)
|
|
373
370
|
|
|
374
371
|
cache_read: Optional[int] = None
|
|
@@ -406,28 +403,28 @@ class Span(Node):
|
|
|
406
403
|
self,
|
|
407
404
|
info: Info[Context, None],
|
|
408
405
|
) -> Optional[SpanIOValue]:
|
|
409
|
-
if self.
|
|
410
|
-
input_value = self.
|
|
406
|
+
if self.db_record:
|
|
407
|
+
input_value = self.db_record.input_value
|
|
411
408
|
if input_value is None or input_value == "":
|
|
412
409
|
return None
|
|
413
410
|
input_value = str(input_value)
|
|
414
|
-
mime_type = self.
|
|
411
|
+
mime_type = self.db_record.input_mime_type
|
|
415
412
|
return SpanIOValue(
|
|
416
413
|
cached_value=input_value,
|
|
417
414
|
mime_type=MimeType(mime_type),
|
|
418
415
|
)
|
|
419
416
|
mime_type, input_value_first_101_chars = await gather(
|
|
420
417
|
info.context.data_loaders.span_fields.load(
|
|
421
|
-
(self.
|
|
418
|
+
(self.id, models.Span.input_mime_type),
|
|
422
419
|
),
|
|
423
420
|
info.context.data_loaders.span_fields.load(
|
|
424
|
-
(self.
|
|
421
|
+
(self.id, models.Span.input_value_first_101_chars),
|
|
425
422
|
),
|
|
426
423
|
)
|
|
427
424
|
if not input_value_first_101_chars:
|
|
428
425
|
return None
|
|
429
426
|
return SpanIOValue(
|
|
430
|
-
span_rowid=self.
|
|
427
|
+
span_rowid=self.id,
|
|
431
428
|
attr=models.Span.input_value,
|
|
432
429
|
truncated_value=truncate_value(input_value_first_101_chars),
|
|
433
430
|
mime_type=MimeType(mime_type),
|
|
@@ -438,28 +435,28 @@ class Span(Node):
|
|
|
438
435
|
self,
|
|
439
436
|
info: Info[Context, None],
|
|
440
437
|
) -> Optional[SpanIOValue]:
|
|
441
|
-
if self.
|
|
442
|
-
output_value = self.
|
|
438
|
+
if self.db_record:
|
|
439
|
+
output_value = self.db_record.output_value
|
|
443
440
|
if output_value is None or output_value == "":
|
|
444
441
|
return None
|
|
445
442
|
output_value = str(output_value)
|
|
446
|
-
mime_type = self.
|
|
443
|
+
mime_type = self.db_record.output_mime_type
|
|
447
444
|
return SpanIOValue(
|
|
448
445
|
cached_value=output_value,
|
|
449
446
|
mime_type=MimeType(mime_type),
|
|
450
447
|
)
|
|
451
448
|
mime_type, output_value_first_101_chars = await gather(
|
|
452
449
|
info.context.data_loaders.span_fields.load(
|
|
453
|
-
(self.
|
|
450
|
+
(self.id, models.Span.output_mime_type),
|
|
454
451
|
),
|
|
455
452
|
info.context.data_loaders.span_fields.load(
|
|
456
|
-
(self.
|
|
453
|
+
(self.id, models.Span.output_value_first_101_chars),
|
|
457
454
|
),
|
|
458
455
|
)
|
|
459
456
|
if not output_value_first_101_chars:
|
|
460
457
|
return None
|
|
461
458
|
return SpanIOValue(
|
|
462
|
-
span_rowid=self.
|
|
459
|
+
span_rowid=self.id,
|
|
463
460
|
attr=models.Span.output_value,
|
|
464
461
|
truncated_value=truncate_value(output_value_first_101_chars),
|
|
465
462
|
mime_type=MimeType(mime_type),
|
|
@@ -470,10 +467,10 @@ class Span(Node):
|
|
|
470
467
|
self,
|
|
471
468
|
info: Info[Context, None],
|
|
472
469
|
) -> list[SpanEvent]:
|
|
473
|
-
if self.
|
|
474
|
-
return [SpanEvent.from_dict(event) for event in self.
|
|
470
|
+
if self.db_record:
|
|
471
|
+
return [SpanEvent.from_dict(event) for event in self.db_record.events]
|
|
475
472
|
value = await info.context.data_loaders.span_fields.load(
|
|
476
|
-
(self.
|
|
473
|
+
(self.id, models.Span.events),
|
|
477
474
|
)
|
|
478
475
|
return [SpanEvent.from_dict(event) for event in value]
|
|
479
476
|
|
|
@@ -485,10 +482,10 @@ class Span(Node):
|
|
|
485
482
|
self,
|
|
486
483
|
info: Info[Context, None],
|
|
487
484
|
) -> Optional[int]:
|
|
488
|
-
if self.
|
|
489
|
-
return self.
|
|
485
|
+
if self.db_record:
|
|
486
|
+
return self.db_record.cumulative_llm_token_count_total
|
|
490
487
|
value = await info.context.data_loaders.span_fields.load(
|
|
491
|
-
(self.
|
|
488
|
+
(self.id, models.Span.cumulative_llm_token_count_total),
|
|
492
489
|
)
|
|
493
490
|
return cast(Optional[int], value)
|
|
494
491
|
|
|
@@ -500,10 +497,10 @@ class Span(Node):
|
|
|
500
497
|
self,
|
|
501
498
|
info: Info[Context, None],
|
|
502
499
|
) -> Optional[int]:
|
|
503
|
-
if self.
|
|
504
|
-
return self.
|
|
500
|
+
if self.db_record:
|
|
501
|
+
return self.db_record.cumulative_llm_token_count_prompt
|
|
505
502
|
value = await info.context.data_loaders.span_fields.load(
|
|
506
|
-
(self.
|
|
503
|
+
(self.id, models.Span.cumulative_llm_token_count_prompt),
|
|
507
504
|
)
|
|
508
505
|
return cast(Optional[int], value)
|
|
509
506
|
|
|
@@ -515,10 +512,10 @@ class Span(Node):
|
|
|
515
512
|
self,
|
|
516
513
|
info: Info[Context, None],
|
|
517
514
|
) -> Optional[int]:
|
|
518
|
-
if self.
|
|
519
|
-
return self.
|
|
515
|
+
if self.db_record:
|
|
516
|
+
return self.db_record.cumulative_llm_token_count_completion
|
|
520
517
|
value = await info.context.data_loaders.span_fields.load(
|
|
521
|
-
(self.
|
|
518
|
+
(self.id, models.Span.cumulative_llm_token_count_completion),
|
|
522
519
|
)
|
|
523
520
|
return cast(Optional[int], value)
|
|
524
521
|
|
|
@@ -530,11 +527,11 @@ class Span(Node):
|
|
|
530
527
|
self,
|
|
531
528
|
info: Info[Context, None],
|
|
532
529
|
) -> SpanStatusCode:
|
|
533
|
-
if self.
|
|
534
|
-
value = self.
|
|
530
|
+
if self.db_record:
|
|
531
|
+
value = self.db_record.cumulative_error_count
|
|
535
532
|
else:
|
|
536
533
|
value = await info.context.data_loaders.span_fields.load(
|
|
537
|
-
(self.
|
|
534
|
+
(self.id, models.Span.cumulative_error_count),
|
|
538
535
|
)
|
|
539
536
|
return SpanStatusCode.ERROR if value else SpanStatusCode.OK
|
|
540
537
|
|
|
@@ -549,7 +546,7 @@ class Span(Node):
|
|
|
549
546
|
sort: Optional[SpanAnnotationSort] = UNSET,
|
|
550
547
|
filter: Optional[AnnotationFilter] = None,
|
|
551
548
|
) -> list[SpanAnnotation]:
|
|
552
|
-
span_id = self.
|
|
549
|
+
span_id = self.id
|
|
553
550
|
annotations = await info.context.data_loaders.span_annotations.load(span_id)
|
|
554
551
|
sort_key = SpanAnnotationColumn.name.value
|
|
555
552
|
sort_descending = False
|
|
@@ -563,18 +560,22 @@ class Span(Node):
|
|
|
563
560
|
annotations.sort(
|
|
564
561
|
key=lambda annotation: getattr(annotation, sort_key), reverse=sort_descending
|
|
565
562
|
)
|
|
566
|
-
return [
|
|
563
|
+
return [
|
|
564
|
+
SpanAnnotation(id=annotation.id, db_record=annotation) for annotation in annotations
|
|
565
|
+
]
|
|
567
566
|
|
|
568
567
|
@strawberry.field(description=("Notes associated with the span.")) # type: ignore
|
|
569
568
|
async def span_notes(
|
|
570
569
|
self,
|
|
571
570
|
info: Info[Context, None],
|
|
572
571
|
) -> list[SpanAnnotation]:
|
|
573
|
-
span_id = self.
|
|
572
|
+
span_id = self.id
|
|
574
573
|
annotations = await info.context.data_loaders.span_annotations.load(span_id)
|
|
575
574
|
annotations = [annotation for annotation in annotations if annotation.name == "note"]
|
|
576
575
|
annotations.sort(key=lambda annotation: getattr(annotation, "created_at"), reverse=False)
|
|
577
|
-
return [
|
|
576
|
+
return [
|
|
577
|
+
SpanAnnotation(id=annotation.id, db_record=annotation) for annotation in annotations
|
|
578
|
+
]
|
|
578
579
|
|
|
579
580
|
@strawberry.field(description="Summarizes each annotation (by name) associated with the span") # type: ignore
|
|
580
581
|
async def span_annotation_summaries(
|
|
@@ -599,7 +600,7 @@ class Span(Node):
|
|
|
599
600
|
- data: A list of dictionaries with label statistics
|
|
600
601
|
"""
|
|
601
602
|
# Load all annotations for this span from the data loader
|
|
602
|
-
annotations = await info.context.data_loaders.span_annotations.load(self.
|
|
603
|
+
annotations = await info.context.data_loaders.span_annotations.load(self.id)
|
|
603
604
|
|
|
604
605
|
# Apply filter if provided to narrow down the annotations
|
|
605
606
|
if filter:
|
|
@@ -643,8 +644,8 @@ class Span(Node):
|
|
|
643
644
|
info: Info[Context, None],
|
|
644
645
|
) -> list[DocumentAnnotation]:
|
|
645
646
|
return [
|
|
646
|
-
|
|
647
|
-
for anno in await info.context.data_loaders.document_evaluations.load(self.
|
|
647
|
+
DocumentAnnotation(id=anno.id, db_record=anno)
|
|
648
|
+
for anno in await info.context.data_loaders.document_evaluations.load(self.id)
|
|
648
649
|
]
|
|
649
650
|
|
|
650
651
|
@strawberry.field(
|
|
@@ -656,21 +657,21 @@ class Span(Node):
|
|
|
656
657
|
evaluation_name: Optional[str] = UNSET,
|
|
657
658
|
) -> list[DocumentRetrievalMetrics]:
|
|
658
659
|
num_documents = (
|
|
659
|
-
self.
|
|
660
|
-
if self.
|
|
660
|
+
self.db_record.num_documents
|
|
661
|
+
if self.db_record
|
|
661
662
|
else await info.context.data_loaders.span_fields.load(
|
|
662
|
-
(self.
|
|
663
|
+
(self.id, models.Span.num_documents),
|
|
663
664
|
)
|
|
664
665
|
)
|
|
665
666
|
if not num_documents:
|
|
666
667
|
return []
|
|
667
668
|
return await info.context.data_loaders.document_retrieval_metrics.load(
|
|
668
|
-
(self.
|
|
669
|
+
(self.id, evaluation_name or None, num_documents),
|
|
669
670
|
)
|
|
670
671
|
|
|
671
672
|
@strawberry.field
|
|
672
673
|
async def num_child_spans(self, info: Info[Context, None]) -> int:
|
|
673
|
-
return await info.context.data_loaders.num_child_spans.load(self.
|
|
674
|
+
return await info.context.data_loaders.num_child_spans.load(self.id)
|
|
674
675
|
|
|
675
676
|
@strawberry.field(
|
|
676
677
|
description="All descendant spans (children, grandchildren, etc.)",
|
|
@@ -699,9 +700,9 @@ class Span(Node):
|
|
|
699
700
|
before=before if isinstance(before, CursorString) else None,
|
|
700
701
|
)
|
|
701
702
|
span_rowids: Iterable[int] = await info.context.data_loaders.span_descendants.load(
|
|
702
|
-
(self.
|
|
703
|
+
(self.id, max_depth or None),
|
|
703
704
|
)
|
|
704
|
-
data = [Span(
|
|
705
|
+
data = [Span(id=span_rowid) for span_rowid in span_rowids]
|
|
705
706
|
return connection_from_list(data=data, args=args)
|
|
706
707
|
|
|
707
708
|
@strawberry.field(
|
|
@@ -712,9 +713,9 @@ class Span(Node):
|
|
|
712
713
|
info: Info[Context, None],
|
|
713
714
|
) -> SpanAsExampleRevision:
|
|
714
715
|
span = (
|
|
715
|
-
self.
|
|
716
|
-
if self.
|
|
717
|
-
else await info.context.data_loaders.span_by_id.load(self.
|
|
716
|
+
self.db_record
|
|
717
|
+
if self.db_record
|
|
718
|
+
else await info.context.data_loaders.span_by_id.load(self.id)
|
|
718
719
|
)
|
|
719
720
|
|
|
720
721
|
# Fetch annotations associated with this span
|
|
@@ -749,16 +750,16 @@ class Span(Node):
|
|
|
749
750
|
]: # use lazy types to avoid circular import: https://strawberry.rocks/docs/types/lazy
|
|
750
751
|
from phoenix.server.api.types.Project import Project
|
|
751
752
|
|
|
752
|
-
span_id = self.
|
|
753
|
+
span_id = self.id
|
|
753
754
|
project = await info.context.data_loaders.span_projects.load(span_id)
|
|
754
|
-
return Project(
|
|
755
|
+
return Project(id=project.id, db_record=project)
|
|
755
756
|
|
|
756
757
|
@strawberry.field(description="Indicates if the span is contained in any dataset") # type: ignore
|
|
757
758
|
async def contained_in_dataset(
|
|
758
759
|
self,
|
|
759
760
|
info: Info[Context, None],
|
|
760
761
|
) -> bool:
|
|
761
|
-
examples = await info.context.data_loaders.span_dataset_examples.load(self.
|
|
762
|
+
examples = await info.context.data_loaders.span_dataset_examples.load(self.id)
|
|
762
763
|
return bool(examples)
|
|
763
764
|
|
|
764
765
|
@strawberry.field(description="Invocation parameters for the span") # type: ignore
|
|
@@ -769,7 +770,7 @@ class Span(Node):
|
|
|
769
770
|
from phoenix.server.api.helpers.playground_clients import OpenAIStreamingClient
|
|
770
771
|
from phoenix.server.api.helpers.playground_registry import PLAYGROUND_CLIENT_REGISTRY
|
|
771
772
|
|
|
772
|
-
db_span: models.Span = await info.context.data_loaders.span_by_id.load(self.
|
|
773
|
+
db_span: models.Span = await info.context.data_loaders.span_by_id.load(self.id)
|
|
773
774
|
attributes = db_span.attributes
|
|
774
775
|
llm_provider = GenerativeProvider.get_model_provider_from_attributes(attributes)
|
|
775
776
|
if llm_provider is None:
|
|
@@ -800,7 +801,7 @@ class Span(Node):
|
|
|
800
801
|
|
|
801
802
|
@strawberry.field
|
|
802
803
|
async def cost_summary(self, info: Info[Context, None]) -> Optional[SpanCostSummary]:
|
|
803
|
-
span_cost = await info.context.data_loaders.span_cost_by_span.load(self.
|
|
804
|
+
span_cost = await info.context.data_loaders.span_cost_by_span.load(self.id)
|
|
804
805
|
if span_cost is None:
|
|
805
806
|
return None
|
|
806
807
|
return SpanCostSummary(
|
|
@@ -823,7 +824,7 @@ class Span(Node):
|
|
|
823
824
|
self, info: Info[Context, None]
|
|
824
825
|
) -> list[SpanCostDetailSummaryEntry]:
|
|
825
826
|
loader = info.context.data_loaders.span_cost_detail_summary_entries_by_span
|
|
826
|
-
entries = await loader.load(self.
|
|
827
|
+
entries = await loader.load(self.id)
|
|
827
828
|
return [
|
|
828
829
|
SpanCostDetailSummaryEntry(
|
|
829
830
|
token_type=entry.token_type,
|