arize-phoenix 11.36.0__py3-none-any.whl → 11.38.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-11.36.0.dist-info → arize_phoenix-11.38.0.dist-info}/METADATA +1 -1
- {arize_phoenix-11.36.0.dist-info → arize_phoenix-11.38.0.dist-info}/RECORD +26 -26
- phoenix/server/api/helpers/playground_clients.py +39 -3
- phoenix/server/api/helpers/playground_spans.py +2 -1
- phoenix/server/api/input_types/ChatCompletionInput.py +2 -0
- phoenix/server/api/input_types/GenerativeModelInput.py +3 -0
- phoenix/server/api/input_types/SpanSort.py +1 -1
- phoenix/server/api/mutations/chat_mutations.py +16 -6
- phoenix/server/api/subscriptions.py +20 -5
- phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +1 -0
- phoenix/server/api/types/Project.py +9 -5
- phoenix/server/api/types/pagination.py +11 -2
- phoenix/server/static/.vite/manifest.json +39 -39
- phoenix/server/static/assets/{components-DVEWtEt2.js → components-BQPHTBfv.js} +418 -345
- phoenix/server/static/assets/{index-D2_lN2VR.js → index-BL5BMgJU.js} +12 -2
- phoenix/server/static/assets/{pages-CJs8SCmq.js → pages-C0Y17J0T.js} +506 -490
- phoenix/server/static/assets/{vendor-DHb1kz-d.js → vendor-BdjZxMii.js} +158 -158
- phoenix/server/static/assets/{vendor-arizeai-BWffpt59.js → vendor-arizeai-CHYlS8jV.js} +1 -1
- phoenix/server/static/assets/{vendor-codemirror-BI6d4ZER.js → vendor-codemirror-Di6t4HnH.js} +3 -3
- phoenix/server/static/assets/{vendor-recharts-lWHIE765.js → vendor-recharts-C9wCDYj3.js} +1 -1
- phoenix/server/static/assets/{vendor-shiki-DbTRJD9G.js → vendor-shiki-MNnmOotP.js} +1 -1
- phoenix/version.py +1 -1
- {arize_phoenix-11.36.0.dist-info → arize_phoenix-11.38.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-11.36.0.dist-info → arize_phoenix-11.38.0.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-11.36.0.dist-info → arize_phoenix-11.38.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-11.36.0.dist-info → arize_phoenix-11.38.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,7 +6,7 @@ phoenix/exceptions.py,sha256=n2L2KKuecrdflB9MsCdAYCiSEvGJptIsfRkXMoJle7A,169
|
|
|
6
6
|
phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
7
7
|
phoenix/services.py,sha256=ngkyKGVatX3cO2WJdo2hKdaVKP-xJCMvqthvga6kJss,5196
|
|
8
8
|
phoenix/settings.py,sha256=2kHfT3BNOVd4dAO1bq-syEQbHSG8oX2-7NhOwK2QREk,896
|
|
9
|
-
phoenix/version.py,sha256=
|
|
9
|
+
phoenix/version.py,sha256=qdksjxkZC4FbFAxxSWV2ZDZvip9ILf88x3Qf3-GYsfw,24
|
|
10
10
|
phoenix/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
phoenix/core/embedding_dimension.py,sha256=zKGbcvwOXgLf-yrJBpQyKtd-LEOPRKHnUToyAU8Owis,87
|
|
12
12
|
phoenix/core/model.py,sha256=qBFraOtmwCCnWJltKNP18DDG0mULXigytlFsa6YOz6k,4837
|
|
@@ -115,7 +115,7 @@ phoenix/server/api/exceptions.py,sha256=9gB4nBRNX6k4_fsQZ12yxw6Tw53h_915l06DYK-q
|
|
|
115
115
|
phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
|
|
116
116
|
phoenix/server/api/queries.py,sha256=oVtlqmYDyRot5_z9jRITeiyb0iIgIXEVteE2fOp-1uA,65096
|
|
117
117
|
phoenix/server/api/schema.py,sha256=fcs36xQwFF_Qe41_5cWR8wYpDvOrnbcyTeo5WNMbDsA,1702
|
|
118
|
-
phoenix/server/api/subscriptions.py,sha256=
|
|
118
|
+
phoenix/server/api/subscriptions.py,sha256=98M9KZK-i7GXVRr17kjwLczy3vd2jPAbrWWCY8Fo_3A,25950
|
|
119
119
|
phoenix/server/api/utils.py,sha256=quCBRcusc6PUq9tJq7M8PgwFZp7nXgVAxtbw8feribY,833
|
|
120
120
|
phoenix/server/api/dataloaders/__init__.py,sha256=wVI-lyHg0XLb2D_Ab53yC5QozSQR8qbd1_tsR1NKMRE,7822
|
|
121
121
|
phoenix/server/api/dataloaders/annotation_configs_by_project.py,sha256=_Nfiug9o01JimU3Z0LpZJ0uaMCjchXomyt_dYAxPFRY,1178
|
|
@@ -183,9 +183,9 @@ phoenix/server/api/helpers/__init__.py,sha256=m2-xaSPqUiSs91k62JaRDjFNfl-1byxBfY
|
|
|
183
183
|
phoenix/server/api/helpers/annotations.py,sha256=9gMXKpMTfWEChoSCnvdWYuyB0hlSnNOp-qUdar9Vono,262
|
|
184
184
|
phoenix/server/api/helpers/dataset_helpers.py,sha256=3bdGBoUzqrtg-sr5p2wpQLOU6dhg_3TKFHNeJj8p0TU,9155
|
|
185
185
|
phoenix/server/api/helpers/experiment_run_filters.py,sha256=DOnVwrmn39eAkk2mwuZP8kIcAnR5jrOgllEwWSjsw94,29893
|
|
186
|
-
phoenix/server/api/helpers/playground_clients.py,sha256=
|
|
186
|
+
phoenix/server/api/helpers/playground_clients.py,sha256=7PuGc5s9uKZjM6uGO85yc0F0HWke3Yn1F6N3dBaukOY,73757
|
|
187
187
|
phoenix/server/api/helpers/playground_registry.py,sha256=n0v4-KnvZJxeaEwOla5qBbnOQjSWznKmMhZnh9ziJt0,2584
|
|
188
|
-
phoenix/server/api/helpers/playground_spans.py,sha256=
|
|
188
|
+
phoenix/server/api/helpers/playground_spans.py,sha256=EDZ0NbkfOXAwGJvLqP2ARE5v6OTtKp9R-KU4AsvX_9U,17176
|
|
189
189
|
phoenix/server/api/helpers/prompts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
190
190
|
phoenix/server/api/helpers/prompts/models.py,sha256=-uMQcFFsA_UwNxdZv0cZZ0m57rzxf8C9Ke2AYolR730,23522
|
|
191
191
|
phoenix/server/api/helpers/prompts/conversions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -194,7 +194,7 @@ phoenix/server/api/helpers/prompts/conversions/aws.py,sha256=6vaT8K13r0bMXB9XHA8
|
|
|
194
194
|
phoenix/server/api/helpers/prompts/conversions/openai.py,sha256=a43WAftFn_me6ePHDufqvlg-4Z2C31owUSsqYC0YUP8,2589
|
|
195
195
|
phoenix/server/api/input_types/AddExamplesToDatasetInput.py,sha256=mIQz0S_z8YdrktKIY6RCvtNJ2yZF9pYvTGgasUsI-54,430
|
|
196
196
|
phoenix/server/api/input_types/AddSpansToDatasetInput.py,sha256=-StSstyMAVrba3tG1U30b-srkKCtu_svflQuSM19iJA,362
|
|
197
|
-
phoenix/server/api/input_types/ChatCompletionInput.py,sha256=
|
|
197
|
+
phoenix/server/api/input_types/ChatCompletionInput.py,sha256=t0fHUl8MVMyYkEvqKsPtTk2J15cyNJQ010mqIk43vYs,1816
|
|
198
198
|
phoenix/server/api/input_types/ChatCompletionMessageInput.py,sha256=0_YQBcoOS3BBTluHIB68DSP8FGAn2D9ZAw-Ht-dkbAQ,822
|
|
199
199
|
phoenix/server/api/input_types/ClearProjectInput.py,sha256=cpPFRyQ3ffy2dLbCZgYpway-mCzhdm4QqnUg8caOBfQ,382
|
|
200
200
|
phoenix/server/api/input_types/ClusterInput.py,sha256=AfhuYYHlYgdMO6Ap8cLXqAp70S0Wutx-RTzZYetN62A,173
|
|
@@ -215,7 +215,7 @@ phoenix/server/api/input_types/DeleteExperimentsInput.py,sha256=4d9N0vSLYbuysAam
|
|
|
215
215
|
phoenix/server/api/input_types/DimensionFilter.py,sha256=eBYcn7ECSJQlEePvbStqkHBRicbIL4vEAzFJwX7bacQ,3137
|
|
216
216
|
phoenix/server/api/input_types/DimensionInput.py,sha256=Vfx5FmiMKey4-EHDQsQRPzSAMRJMN5oVMLDUl4NKAa8,164
|
|
217
217
|
phoenix/server/api/input_types/GenerativeCredentialInput.py,sha256=sEM9UtgDMMuhImLwGXctD8BWDs2V3hNQ1mosoklRZvc,219
|
|
218
|
-
phoenix/server/api/input_types/GenerativeModelInput.py,sha256=
|
|
218
|
+
phoenix/server/api/input_types/GenerativeModelInput.py,sha256=M9R5LmLjyxOYPEIiann4ln23degOWJ2GTIk64bi73yI,841
|
|
219
219
|
phoenix/server/api/input_types/Granularity.py,sha256=dbBlD_GsIBa8_xrx4JlLuR59bQ0NRB5H-cv1zvcb-cw,2299
|
|
220
220
|
phoenix/server/api/input_types/InvocationParameters.py,sha256=62xL0iIKvuQherkuJaJ6Lha4TTEoYLpvH-pEP9awK6k,5260
|
|
221
221
|
phoenix/server/api/input_types/PatchAnnotationInput.py,sha256=2wxC-ibQU59I28amTxLMYMo9SSvJwAIor0w0YvS0e48,676
|
|
@@ -230,7 +230,7 @@ phoenix/server/api/input_types/PromptTemplateOptions.py,sha256=8ZJdH1F9fExcdH9dF
|
|
|
230
230
|
phoenix/server/api/input_types/PromptVersionInput.py,sha256=6iFWf2Ye9K1dwL1810L-wUTLkMtOIHemJTxar4xF4kw,3911
|
|
231
231
|
phoenix/server/api/input_types/SpanAnnotationFilter.py,sha256=-djfIXYCxV6sV3GPOZQUV0SPfiWDhRlTORfeQ7tCBgQ,2671
|
|
232
232
|
phoenix/server/api/input_types/SpanAnnotationSort.py,sha256=T5pAGzmh4MiJp9JMAzNDByFVTczfw02FH4WFWwFezyI,361
|
|
233
|
-
phoenix/server/api/input_types/SpanSort.py,sha256=
|
|
233
|
+
phoenix/server/api/input_types/SpanSort.py,sha256=1AHrqx3HuVKsp9DSaDsQMAyid4Au3kqY38mE9x0nPBU,7552
|
|
234
234
|
phoenix/server/api/input_types/TimeBinConfig.py,sha256=s4p0SNTGRY6rbHfZhEMwmon5zX85j-DbN06GkapF6jg,516
|
|
235
235
|
phoenix/server/api/input_types/TimeRange.py,sha256=pwhC2jx6dFIgT0qFfnO68qiJp9-m7Je5QkNscNsuVxA,700
|
|
236
236
|
phoenix/server/api/input_types/TraceAnnotationSort.py,sha256=BzwiUnMh2VsgQYnhDlbJ6ljHugqIS4YDUlYzvq_tl3o,365
|
|
@@ -239,7 +239,7 @@ phoenix/server/api/input_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
|
|
|
239
239
|
phoenix/server/api/mutations/__init__.py,sha256=DlAwXDKQzOpY4vFiDUR9Cu2kmncFr4m-RPRyQABBPIE,1972
|
|
240
240
|
phoenix/server/api/mutations/annotation_config_mutations.py,sha256=i7NsQhYICcQ-I-tnFjGtVAYc8WVmMBacmRaqHWJ25t4,15433
|
|
241
241
|
phoenix/server/api/mutations/api_key_mutations.py,sha256=nfnRjALCaQMi_jIbEPW4G3Dn3tPnmZVU11tpBbBijGA,6242
|
|
242
|
-
phoenix/server/api/mutations/chat_mutations.py,sha256=
|
|
242
|
+
phoenix/server/api/mutations/chat_mutations.py,sha256=rdYFaqaTqbDpF_55n80seIPBs_LhkmKXEzFVJwq8t-A,25106
|
|
243
243
|
phoenix/server/api/mutations/dataset_mutations.py,sha256=KRlF-Ag3twqaBpLR_6WYxf57DffaGuFBm-soaBPStbI,27787
|
|
244
244
|
phoenix/server/api/mutations/experiment_mutations.py,sha256=p3CoLAa8nFPa3D759Y2A7De_PVJNGOL98mA3HoZBrRQ,3188
|
|
245
245
|
phoenix/server/api/mutations/export_events_mutations.py,sha256=xoDnVWC7eA_8wNQP0-oyiHojyUZ0EhVVSrsAnztetC0,3993
|
|
@@ -285,7 +285,7 @@ phoenix/server/api/types/AnnotatorKind.py,sha256=6L_1iuxYYwmEMdKNlET1bPKhJ-INfCs
|
|
|
285
285
|
phoenix/server/api/types/ApiKey.py,sha256=76HIkWxyJqL3UjdMesX9l5y6XaD9QphwabXGQVY-MaQ,793
|
|
286
286
|
phoenix/server/api/types/AuthMethod.py,sha256=M25usT6FCNKi-QFMdtMqRjJVGfq1ACnVoSjHXGxfrUk,126
|
|
287
287
|
phoenix/server/api/types/ChatCompletionMessageRole.py,sha256=kmQOilOlVntlmqbaHkqXZuimfljfYaHc3kbo53uK8_0,227
|
|
288
|
-
phoenix/server/api/types/ChatCompletionSubscriptionPayload.py,sha256=
|
|
288
|
+
phoenix/server/api/types/ChatCompletionSubscriptionPayload.py,sha256=P06QWwK4LwU51cVQqBath__6cJgqhMeSV3_0h0pairY,1075
|
|
289
289
|
phoenix/server/api/types/Cluster.py,sha256=duX0pSC7P3YT1IztduuJtPsRj1x6oOOLfmWf2Y-FdEk,5699
|
|
290
290
|
phoenix/server/api/types/CostBreakdown.py,sha256=yw9dlb0blGIB_dWNP8yEvDHJztHjpiV6_CN7waC-ILY,292
|
|
291
291
|
phoenix/server/api/types/CreateDatasetPayload.py,sha256=R-6zCmuD0f76RU9Giu78xwTHlASQs6Aq8yzvX1Kxc3g,140
|
|
@@ -332,7 +332,7 @@ phoenix/server/api/types/ModelInterface.py,sha256=Qe7H23wDb_Q2-HmeY2t0R5Jsn4aAfY
|
|
|
332
332
|
phoenix/server/api/types/NumericRange.py,sha256=afEjgF97Go_OvmjMggbPBt-zGM8IONewAyEiKEHRds0,192
|
|
333
333
|
phoenix/server/api/types/PerformanceMetric.py,sha256=KFkmJDqP43eDUtARQOUqR7NYcxvL6Vh2uisHWU6H3ko,387
|
|
334
334
|
phoenix/server/api/types/PlaygroundModel.py,sha256=IqJFxsAAJMRyaFI9ryI3GQrpFOJ5Llf6kIutEO-tFvM,321
|
|
335
|
-
phoenix/server/api/types/Project.py,sha256=
|
|
335
|
+
phoenix/server/api/types/Project.py,sha256=klaowPuWXVz6tFQEA10gL1pY554H-nPFNtLcUSGGMxk,72289
|
|
336
336
|
phoenix/server/api/types/ProjectSession.py,sha256=uwqTsDTfSGz13AvP-cwS_mJR5JZ1lHqu10ungbl7g5s,6245
|
|
337
337
|
phoenix/server/api/types/ProjectTraceRetentionPolicy.py,sha256=tYy2kgalPDyuaYZr0VUHjH0YpXaiF_QOzg5yfaV_c7c,3782
|
|
338
338
|
phoenix/server/api/types/Prompt.py,sha256=ad52KVQ1yJrAWXd3HdOKKHzyaUJqrp2mtFEe1QGEE4E,5455
|
|
@@ -368,7 +368,7 @@ phoenix/server/api/types/ValidationResult.py,sha256=pHwdYk4J7SJ5xhlWWHg_6qWkfk4r
|
|
|
368
368
|
phoenix/server/api/types/VectorDriftMetricEnum.py,sha256=etiJM5ZjQuD-oE7sY-FbdIKY050jk3IU49IMwmfJbEc,188
|
|
369
369
|
phoenix/server/api/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
370
370
|
phoenix/server/api/types/node.py,sha256=ya1kJz6ok0LEiMMJOvV6s6nr_biWBZWAiC9JEtR-ki8,1073
|
|
371
|
-
phoenix/server/api/types/pagination.py,sha256=
|
|
371
|
+
phoenix/server/api/types/pagination.py,sha256=GJktCIGRfbuFh8kHJzJ0QTzs6ZDtAJizgjSSObnBCeM,9342
|
|
372
372
|
phoenix/server/cost_tracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
373
373
|
phoenix/server/cost_tracking/cost_details_calculator.py,sha256=Tt0YcuLhgPuXKWJemWVmYQfG0xQUvH4VziIj6KcDnoA,8945
|
|
374
374
|
phoenix/server/cost_tracking/cost_model_lookup.py,sha256=jhtVdnQBzrTUHeOGPWgOebk-Io5hpJ1vAgWOu8ojeJ4,6801
|
|
@@ -402,16 +402,16 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
|
|
|
402
402
|
phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
|
|
403
403
|
phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
|
|
404
404
|
phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
|
|
405
|
-
phoenix/server/static/.vite/manifest.json,sha256=
|
|
406
|
-
phoenix/server/static/assets/components-
|
|
407
|
-
phoenix/server/static/assets/index-
|
|
408
|
-
phoenix/server/static/assets/pages-
|
|
405
|
+
phoenix/server/static/.vite/manifest.json,sha256=Np5_hrBhv-sxSpgLXqSzTLqNrO4ZJL8b1pjPLo3VY_A,2328
|
|
406
|
+
phoenix/server/static/assets/components-BQPHTBfv.js,sha256=KsHdnFEEI0Hu2clO50tf-nkY5hjfloIvGCcDTgOwJd8,683766
|
|
407
|
+
phoenix/server/static/assets/index-BL5BMgJU.js,sha256=VYFmRz6mUFpwK9qtMJy8mASErNfKQf4HiU3mARLGFDE,63435
|
|
408
|
+
phoenix/server/static/assets/pages-C0Y17J0T.js,sha256=ugjTmAk-TgcWzcp06zt8Lc--BzjshWE652U8AbUWfCA,1305719
|
|
409
409
|
phoenix/server/static/assets/vendor-BGzfc4EU.css,sha256=Nx5Lmx-bqYR7nsO_O4kEBcrJ8cwknWjZ6seHN3_s4UQ,3171
|
|
410
|
-
phoenix/server/static/assets/vendor-
|
|
411
|
-
phoenix/server/static/assets/vendor-arizeai-
|
|
412
|
-
phoenix/server/static/assets/vendor-codemirror-
|
|
413
|
-
phoenix/server/static/assets/vendor-recharts-
|
|
414
|
-
phoenix/server/static/assets/vendor-shiki-
|
|
410
|
+
phoenix/server/static/assets/vendor-BdjZxMii.js,sha256=CEEWyhdR8PcZfr9EntiJVBEN3hoFmS3hnvxQapcB57M,2591438
|
|
411
|
+
phoenix/server/static/assets/vendor-arizeai-CHYlS8jV.js,sha256=AEKxh9WhnE-QrWus26WBBR0Fq1fh2r1iXPl3BFU7quk,112652
|
|
412
|
+
phoenix/server/static/assets/vendor-codemirror-Di6t4HnH.js,sha256=4grodwIcHPZTnaKyCM8LqhYr7xQh6sQfICc-eQ_5l2c,413213
|
|
413
|
+
phoenix/server/static/assets/vendor-recharts-C9wCDYj3.js,sha256=_vwHqxWoiaeY2yKMKGQxyb62QorGUX0Y9kv-jE0JAMA,231654
|
|
414
|
+
phoenix/server/static/assets/vendor-shiki-MNnmOotP.js,sha256=gXLCqndUHWJUssTPN2s4nOnxBMlnGyWb2XmIwogQfLs,305160
|
|
415
415
|
phoenix/server/static/assets/vendor-three-BLWp5bic.js,sha256=vfSCVXS20jA0Ceo_O0mDxYBcROinWMdPE6RR4JXmtec,620972
|
|
416
416
|
phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
417
417
|
phoenix/server/templates/index.html,sha256=QAYh0TG5mg-GvDQUR09aD9ebl9Sfq0fYAcfIa5G7J6E,7148
|
|
@@ -451,9 +451,9 @@ phoenix/utilities/project.py,sha256=auVpARXkDb-JgeX5f2aStyFIkeKvGwN9l7qrFeJMVxI,
|
|
|
451
451
|
phoenix/utilities/re.py,sha256=6YyUWIkv0zc2SigsxfOWIHzdpjKA_TZo2iqKq7zJKvw,2081
|
|
452
452
|
phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
453
453
|
phoenix/utilities/template_formatters.py,sha256=gh9PJD6WEGw7TEYXfSst1UR4pWWwmjxMLrDVQ_CkpkQ,2779
|
|
454
|
-
arize_phoenix-11.
|
|
455
|
-
arize_phoenix-11.
|
|
456
|
-
arize_phoenix-11.
|
|
457
|
-
arize_phoenix-11.
|
|
458
|
-
arize_phoenix-11.
|
|
459
|
-
arize_phoenix-11.
|
|
454
|
+
arize_phoenix-11.38.0.dist-info/METADATA,sha256=vH-e4dAtKlBTRxSfc0XHZdsij_kO0mq0SNlAfMXMfSM,34045
|
|
455
|
+
arize_phoenix-11.38.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
456
|
+
arize_phoenix-11.38.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
|
|
457
|
+
arize_phoenix-11.38.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
|
|
458
|
+
arize_phoenix-11.38.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
|
|
459
|
+
arize_phoenix-11.38.0.dist-info/RECORD,,
|
|
@@ -57,6 +57,7 @@ from phoenix.server.api.types.GenerativeProvider import GenerativeProviderKey
|
|
|
57
57
|
if TYPE_CHECKING:
|
|
58
58
|
import httpx
|
|
59
59
|
from anthropic.types import MessageParam, TextBlockParam, ToolResultBlockParam
|
|
60
|
+
from botocore.awsrequest import AWSPreparedRequest # type: ignore[import-untyped]
|
|
60
61
|
from google.generativeai.types import ContentType
|
|
61
62
|
from openai import AsyncAzureOpenAI, AsyncOpenAI
|
|
62
63
|
from openai.types import CompletionUsage
|
|
@@ -546,6 +547,7 @@ class DeepSeekStreamingClient(OpenAIBaseStreamingClient):
|
|
|
546
547
|
client = AsyncOpenAI(
|
|
547
548
|
api_key=api_key,
|
|
548
549
|
base_url=base_url or "https://api.deepseek.com",
|
|
550
|
+
default_headers=model.custom_headers or None,
|
|
549
551
|
)
|
|
550
552
|
super().__init__(client=client, model=model, credentials=credentials)
|
|
551
553
|
# DeepSeek uses OpenAI-compatible API but we'll track it as a separate provider
|
|
@@ -587,6 +589,7 @@ class XAIStreamingClient(OpenAIBaseStreamingClient):
|
|
|
587
589
|
client = AsyncOpenAI(
|
|
588
590
|
api_key=api_key,
|
|
589
591
|
base_url=base_url or "https://api.x.ai/v1",
|
|
592
|
+
default_headers=model.custom_headers or None,
|
|
590
593
|
)
|
|
591
594
|
super().__init__(client=client, model=model, credentials=credentials)
|
|
592
595
|
# xAI uses OpenAI-compatible API but we'll track it as a separate provider
|
|
@@ -624,7 +627,11 @@ class OllamaStreamingClient(OpenAIBaseStreamingClient):
|
|
|
624
627
|
if not base_url:
|
|
625
628
|
raise BadRequest("An Ollama base URL is required for Ollama models")
|
|
626
629
|
api_key = "ollama"
|
|
627
|
-
client = AsyncOpenAI(
|
|
630
|
+
client = AsyncOpenAI(
|
|
631
|
+
api_key=api_key,
|
|
632
|
+
base_url=base_url,
|
|
633
|
+
default_headers=model.custom_headers or None,
|
|
634
|
+
)
|
|
628
635
|
super().__init__(client=client, model=model, credentials=credentials)
|
|
629
636
|
# Ollama uses OpenAI-compatible API but we'll track it as a separate provider
|
|
630
637
|
# Adding a custom "ollama" provider value to make it distinguishable in traces
|
|
@@ -679,6 +686,7 @@ class BedrockStreamingClient(PlaygroundStreamingClient):
|
|
|
679
686
|
super().__init__(model=model, credentials=credentials)
|
|
680
687
|
self.region = model.region or "us-east-1"
|
|
681
688
|
self.api = "converse"
|
|
689
|
+
self.custom_headers = model.custom_headers or {}
|
|
682
690
|
self.aws_access_key_id = _get_credential_value(credentials, "AWS_ACCESS_KEY_ID") or getenv(
|
|
683
691
|
"AWS_ACCESS_KEY_ID"
|
|
684
692
|
)
|
|
@@ -697,9 +705,24 @@ class BedrockStreamingClient(PlaygroundStreamingClient):
|
|
|
697
705
|
aws_session_token=self.aws_session_token,
|
|
698
706
|
)
|
|
699
707
|
|
|
708
|
+
# Add custom headers support via boto3 event system
|
|
709
|
+
if self.custom_headers:
|
|
710
|
+
self._setup_custom_headers(self.client, self.custom_headers)
|
|
711
|
+
|
|
700
712
|
self._attributes[LLM_PROVIDER] = "aws"
|
|
701
713
|
self._attributes[LLM_SYSTEM] = "aws"
|
|
702
714
|
|
|
715
|
+
@staticmethod
|
|
716
|
+
def _setup_custom_headers(client: Any, custom_headers: Mapping[str, str]) -> None:
|
|
717
|
+
"""Setup custom headers using boto3's event system."""
|
|
718
|
+
if not custom_headers:
|
|
719
|
+
return
|
|
720
|
+
|
|
721
|
+
def add_custom_headers(request: "AWSPreparedRequest", **kwargs: Any) -> None:
|
|
722
|
+
request.headers.update(custom_headers)
|
|
723
|
+
|
|
724
|
+
client.meta.events.register("before-send.*", add_custom_headers)
|
|
725
|
+
|
|
703
726
|
@classmethod
|
|
704
727
|
def dependencies(cls) -> list[Dependency]:
|
|
705
728
|
return [Dependency(name="boto3")]
|
|
@@ -756,6 +779,9 @@ class BedrockStreamingClient(PlaygroundStreamingClient):
|
|
|
756
779
|
aws_secret_access_key=self.aws_secret_access_key,
|
|
757
780
|
aws_session_token=self.aws_session_token,
|
|
758
781
|
)
|
|
782
|
+
# Re-setup custom headers for the new client
|
|
783
|
+
if self.custom_headers:
|
|
784
|
+
self._setup_custom_headers(self.client, self.custom_headers)
|
|
759
785
|
if self.api == "invoke":
|
|
760
786
|
async for chunk in self._handle_invoke_api(messages, tools, invocation_parameters):
|
|
761
787
|
yield chunk
|
|
@@ -1140,7 +1166,12 @@ class OpenAIStreamingClient(OpenAIBaseStreamingClient):
|
|
|
1140
1166
|
raise BadRequest("An API key is required for OpenAI models")
|
|
1141
1167
|
api_key = "sk-fake-api-key"
|
|
1142
1168
|
|
|
1143
|
-
client = AsyncOpenAI(
|
|
1169
|
+
client = AsyncOpenAI(
|
|
1170
|
+
api_key=api_key,
|
|
1171
|
+
base_url=base_url,
|
|
1172
|
+
default_headers=model.custom_headers or None,
|
|
1173
|
+
timeout=30,
|
|
1174
|
+
)
|
|
1144
1175
|
super().__init__(client=client, model=model, credentials=credentials)
|
|
1145
1176
|
self._attributes[LLM_PROVIDER] = OpenInferenceLLMProviderValues.OPENAI.value
|
|
1146
1177
|
self._attributes[LLM_SYSTEM] = OpenInferenceLLMSystemValues.OPENAI.value
|
|
@@ -1295,6 +1326,7 @@ class AzureOpenAIStreamingClient(OpenAIBaseStreamingClient):
|
|
|
1295
1326
|
api_key=api_key,
|
|
1296
1327
|
azure_endpoint=endpoint,
|
|
1297
1328
|
api_version=api_version,
|
|
1329
|
+
default_headers=model.custom_headers or None,
|
|
1298
1330
|
)
|
|
1299
1331
|
else:
|
|
1300
1332
|
try:
|
|
@@ -1312,6 +1344,7 @@ class AzureOpenAIStreamingClient(OpenAIBaseStreamingClient):
|
|
|
1312
1344
|
),
|
|
1313
1345
|
azure_endpoint=endpoint,
|
|
1314
1346
|
api_version=api_version,
|
|
1347
|
+
default_headers=model.custom_headers or None,
|
|
1315
1348
|
)
|
|
1316
1349
|
super().__init__(client=client, model=model, credentials=credentials)
|
|
1317
1350
|
self._attributes[LLM_PROVIDER] = OpenInferenceLLMProviderValues.AZURE.value
|
|
@@ -1459,7 +1492,10 @@ class AnthropicStreamingClient(PlaygroundStreamingClient):
|
|
|
1459
1492
|
if not api_key:
|
|
1460
1493
|
raise BadRequest("An API key is required for Anthropic models")
|
|
1461
1494
|
|
|
1462
|
-
self.client = anthropic.AsyncAnthropic(
|
|
1495
|
+
self.client = anthropic.AsyncAnthropic(
|
|
1496
|
+
api_key=api_key,
|
|
1497
|
+
default_headers=model.custom_headers or None,
|
|
1498
|
+
)
|
|
1463
1499
|
self.model_name = model.name
|
|
1464
1500
|
self.rate_limiter = PlaygroundRateLimiter(model.provider_key, anthropic.RateLimitError)
|
|
1465
1501
|
self.client._client = _HttpxClient(self.client._client, self._attributes)
|
|
@@ -222,6 +222,7 @@ def get_db_experiment_run(
|
|
|
222
222
|
*,
|
|
223
223
|
experiment_id: int,
|
|
224
224
|
example_id: int,
|
|
225
|
+
repetition_number: int,
|
|
225
226
|
) -> models.ExperimentRun:
|
|
226
227
|
return models.ExperimentRun(
|
|
227
228
|
experiment_id=experiment_id,
|
|
@@ -230,7 +231,7 @@ def get_db_experiment_run(
|
|
|
230
231
|
output=models.ExperimentRunOutput(
|
|
231
232
|
task_output=get_dataset_example_output(db_span),
|
|
232
233
|
),
|
|
233
|
-
repetition_number=
|
|
234
|
+
repetition_number=repetition_number,
|
|
234
235
|
start_time=db_span.start_time,
|
|
235
236
|
end_time=db_span.end_time,
|
|
236
237
|
error=db_span.status_message or None,
|
|
@@ -26,6 +26,7 @@ class ChatCompletionInput:
|
|
|
26
26
|
credentials: Optional[list[GenerativeCredentialInput]] = UNSET
|
|
27
27
|
template: Optional[PromptTemplateOptions] = UNSET
|
|
28
28
|
prompt_name: Optional[Identifier] = None
|
|
29
|
+
repetitions: int
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
@strawberry.input
|
|
@@ -36,6 +37,7 @@ class ChatCompletionOverDatasetInput:
|
|
|
36
37
|
tools: Optional[list[JSON]] = UNSET
|
|
37
38
|
credentials: Optional[list[GenerativeCredentialInput]] = UNSET
|
|
38
39
|
template_format: PromptTemplateFormat = PromptTemplateFormat.MUSTACHE
|
|
40
|
+
repetitions: int
|
|
39
41
|
dataset_id: GlobalID
|
|
40
42
|
dataset_version_id: Optional[GlobalID] = None
|
|
41
43
|
experiment_name: Optional[str] = None
|
|
@@ -2,6 +2,7 @@ from typing import Optional
|
|
|
2
2
|
|
|
3
3
|
import strawberry
|
|
4
4
|
from strawberry import UNSET
|
|
5
|
+
from strawberry.scalars import JSON
|
|
5
6
|
|
|
6
7
|
from phoenix.server.api.types.GenerativeProvider import GenerativeProviderKey
|
|
7
8
|
|
|
@@ -19,3 +20,5 @@ class GenerativeModelInput:
|
|
|
19
20
|
""" The API version to use for the model. """
|
|
20
21
|
region: Optional[str] = UNSET
|
|
21
22
|
""" The region to use for the model. """
|
|
23
|
+
custom_headers: Optional[JSON] = UNSET
|
|
24
|
+
""" Custom headers to use for the model. """
|
|
@@ -199,7 +199,7 @@ class SpanSort:
|
|
|
199
199
|
models.SpanAnnotation.span_rowid == models.Span.id,
|
|
200
200
|
models.SpanAnnotation.name == eval_name,
|
|
201
201
|
),
|
|
202
|
-
).order_by(expr)
|
|
202
|
+
).order_by(nulls_last(expr))
|
|
203
203
|
return SpanSortConfig(
|
|
204
204
|
stmt=stmt,
|
|
205
205
|
orm_expression=eval_result_key.attr.orm_expression,
|
|
@@ -112,6 +112,7 @@ class ChatCompletionMutationError:
|
|
|
112
112
|
@strawberry.type
|
|
113
113
|
class ChatCompletionOverDatasetMutationExamplePayload:
|
|
114
114
|
dataset_example_id: GlobalID
|
|
115
|
+
repetition_number: int
|
|
115
116
|
experiment_run_id: GlobalID
|
|
116
117
|
result: Union[ChatCompletionMutationPayload, ChatCompletionMutationError]
|
|
117
118
|
|
|
@@ -207,7 +208,12 @@ class ChatCompletionMutationMixin:
|
|
|
207
208
|
results: list[Union[ChatCompletionMutationPayload, BaseException]] = []
|
|
208
209
|
batch_size = 3
|
|
209
210
|
start_time = datetime.now(timezone.utc)
|
|
210
|
-
|
|
211
|
+
unbatched_items = [
|
|
212
|
+
(revision, repetition_number)
|
|
213
|
+
for revision in revisions
|
|
214
|
+
for repetition_number in range(1, input.repetitions + 1)
|
|
215
|
+
]
|
|
216
|
+
for batch in _get_batches(unbatched_items, batch_size):
|
|
211
217
|
batch_results = await asyncio.gather(
|
|
212
218
|
*(
|
|
213
219
|
cls._chat_completion(
|
|
@@ -224,10 +230,11 @@ class ChatCompletionMutationMixin:
|
|
|
224
230
|
variables=revision.input,
|
|
225
231
|
),
|
|
226
232
|
prompt_name=input.prompt_name,
|
|
233
|
+
repetitions=repetition_number,
|
|
227
234
|
),
|
|
228
235
|
project_name=project_name,
|
|
229
236
|
)
|
|
230
|
-
for revision in batch
|
|
237
|
+
for revision, repetition_number in batch
|
|
231
238
|
),
|
|
232
239
|
return_exceptions=True,
|
|
233
240
|
)
|
|
@@ -239,13 +246,13 @@ class ChatCompletionMutationMixin:
|
|
|
239
246
|
experiment_id=GlobalID(models.Experiment.__name__, str(experiment.id)),
|
|
240
247
|
)
|
|
241
248
|
experiment_runs = []
|
|
242
|
-
for revision, result in zip(
|
|
249
|
+
for (revision, repetition_number), result in zip(unbatched_items, results):
|
|
243
250
|
if isinstance(result, BaseException):
|
|
244
251
|
experiment_run = models.ExperimentRun(
|
|
245
252
|
experiment_id=experiment.id,
|
|
246
253
|
dataset_example_id=revision.dataset_example_id,
|
|
247
254
|
output={},
|
|
248
|
-
repetition_number=
|
|
255
|
+
repetition_number=repetition_number,
|
|
249
256
|
start_time=start_time,
|
|
250
257
|
end_time=start_time,
|
|
251
258
|
error=str(result),
|
|
@@ -261,7 +268,7 @@ class ChatCompletionMutationMixin:
|
|
|
261
268
|
),
|
|
262
269
|
prompt_token_count=db_span.cumulative_llm_token_count_prompt,
|
|
263
270
|
completion_token_count=db_span.cumulative_llm_token_count_completion,
|
|
264
|
-
repetition_number=
|
|
271
|
+
repetition_number=repetition_number,
|
|
265
272
|
start_time=db_span.start_time,
|
|
266
273
|
end_time=db_span.end_time,
|
|
267
274
|
error=str(result.error_message) if result.error_message else None,
|
|
@@ -272,13 +279,16 @@ class ChatCompletionMutationMixin:
|
|
|
272
279
|
session.add_all(experiment_runs)
|
|
273
280
|
await session.flush()
|
|
274
281
|
|
|
275
|
-
for revision, experiment_run, result in zip(
|
|
282
|
+
for (revision, repetition_number), experiment_run, result in zip(
|
|
283
|
+
unbatched_items, experiment_runs, results
|
|
284
|
+
):
|
|
276
285
|
dataset_example_id = GlobalID(
|
|
277
286
|
models.DatasetExample.__name__, str(revision.dataset_example_id)
|
|
278
287
|
)
|
|
279
288
|
experiment_run_id = GlobalID(models.ExperimentRun.__name__, str(experiment_run.id))
|
|
280
289
|
example_payload = ChatCompletionOverDatasetMutationExamplePayload(
|
|
281
290
|
dataset_example_id=dataset_example_id,
|
|
291
|
+
repetition_number=repetition_number,
|
|
282
292
|
experiment_run_id=experiment_run_id,
|
|
283
293
|
result=result
|
|
284
294
|
if isinstance(result, ChatCompletionMutationPayload)
|
|
@@ -308,7 +308,7 @@ class Subscription:
|
|
|
308
308
|
name=input.experiment_name
|
|
309
309
|
or _default_playground_experiment_name(input.prompt_name),
|
|
310
310
|
description=input.experiment_description,
|
|
311
|
-
repetitions=
|
|
311
|
+
repetitions=input.repetitions,
|
|
312
312
|
metadata_=input.experiment_metadata or dict(),
|
|
313
313
|
project_name=project_name,
|
|
314
314
|
)
|
|
@@ -327,11 +327,13 @@ class Subscription:
|
|
|
327
327
|
llm_client=llm_client,
|
|
328
328
|
revision=revision,
|
|
329
329
|
results=results,
|
|
330
|
+
repetition_number=repetition_number,
|
|
330
331
|
experiment_id=experiment.id,
|
|
331
332
|
project_id=playground_project_id,
|
|
332
333
|
),
|
|
333
334
|
)
|
|
334
335
|
for revision in revisions
|
|
336
|
+
for repetition_number in range(1, input.repetitions + 1)
|
|
335
337
|
]
|
|
336
338
|
in_progress: list[
|
|
337
339
|
tuple[
|
|
@@ -409,6 +411,7 @@ async def _stream_chat_completion_over_dataset_example(
|
|
|
409
411
|
input: ChatCompletionOverDatasetInput,
|
|
410
412
|
llm_client: PlaygroundStreamingClient,
|
|
411
413
|
revision: models.DatasetExampleRevision,
|
|
414
|
+
repetition_number: int,
|
|
412
415
|
results: asyncio.Queue[ChatCompletionResult],
|
|
413
416
|
experiment_id: int,
|
|
414
417
|
project_id: int,
|
|
@@ -435,7 +438,11 @@ async def _stream_chat_completion_over_dataset_example(
|
|
|
435
438
|
)
|
|
436
439
|
except TemplateFormatterError as error:
|
|
437
440
|
format_end_time = cast(datetime, normalize_datetime(dt=local_now(), tz=timezone.utc))
|
|
438
|
-
yield ChatCompletionSubscriptionError(
|
|
441
|
+
yield ChatCompletionSubscriptionError(
|
|
442
|
+
message=str(error),
|
|
443
|
+
dataset_example_id=example_id,
|
|
444
|
+
repetition_number=repetition_number,
|
|
445
|
+
)
|
|
439
446
|
await results.put(
|
|
440
447
|
(
|
|
441
448
|
example_id,
|
|
@@ -445,7 +452,7 @@ async def _stream_chat_completion_over_dataset_example(
|
|
|
445
452
|
dataset_example_id=revision.dataset_example_id,
|
|
446
453
|
trace_id=None,
|
|
447
454
|
output={},
|
|
448
|
-
repetition_number=
|
|
455
|
+
repetition_number=repetition_number,
|
|
449
456
|
start_time=format_start_time,
|
|
450
457
|
end_time=format_end_time,
|
|
451
458
|
error=str(error),
|
|
@@ -465,17 +472,24 @@ async def _stream_chat_completion_over_dataset_example(
|
|
|
465
472
|
):
|
|
466
473
|
span.add_response_chunk(chunk)
|
|
467
474
|
chunk.dataset_example_id = example_id
|
|
475
|
+
chunk.repetition_number = repetition_number
|
|
468
476
|
yield chunk
|
|
469
477
|
span.set_attributes(llm_client.attributes)
|
|
470
478
|
db_trace = get_db_trace(span, project_id)
|
|
471
479
|
db_span = get_db_span(span, db_trace)
|
|
472
480
|
db_run = get_db_experiment_run(
|
|
473
|
-
db_span,
|
|
481
|
+
db_span,
|
|
482
|
+
db_trace,
|
|
483
|
+
experiment_id=experiment_id,
|
|
484
|
+
example_id=revision.dataset_example_id,
|
|
485
|
+
repetition_number=repetition_number,
|
|
474
486
|
)
|
|
475
487
|
await results.put((example_id, db_span, db_run))
|
|
476
488
|
if span.status_message is not None:
|
|
477
489
|
yield ChatCompletionSubscriptionError(
|
|
478
|
-
message=span.status_message,
|
|
490
|
+
message=span.status_message,
|
|
491
|
+
dataset_example_id=example_id,
|
|
492
|
+
repetition_number=repetition_number,
|
|
479
493
|
)
|
|
480
494
|
|
|
481
495
|
|
|
@@ -511,6 +525,7 @@ async def _chat_completion_result_payloads(
|
|
|
511
525
|
span=Span(span_rowid=span.id, db_span=span) if span else None,
|
|
512
526
|
experiment_run=to_gql_experiment_run(run),
|
|
513
527
|
dataset_example_id=example_id,
|
|
528
|
+
repetition_number=run.repetition_number,
|
|
514
529
|
)
|
|
515
530
|
|
|
516
531
|
|
|
@@ -355,12 +355,16 @@ class Project(Node):
|
|
|
355
355
|
if sort_config and cursor.sort_column:
|
|
356
356
|
sort_column = cursor.sort_column
|
|
357
357
|
compare = operator.lt if sort_config.dir is SortDir.desc else operator.gt
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
358
|
+
if sort_column.type is CursorSortColumnDataType.NULL:
|
|
359
|
+
stmt = stmt.where(sort_config.orm_expression.is_(None))
|
|
360
|
+
stmt = stmt.where(compare(models.Span.id, cursor.rowid))
|
|
361
|
+
else:
|
|
362
|
+
stmt = stmt.where(
|
|
363
|
+
compare(
|
|
364
|
+
tuple_(sort_config.orm_expression, models.Span.id),
|
|
365
|
+
(sort_column.value, cursor.rowid),
|
|
366
|
+
)
|
|
362
367
|
)
|
|
363
|
-
)
|
|
364
368
|
else:
|
|
365
369
|
stmt = stmt.where(models.Span.id > cursor.rowid)
|
|
366
370
|
stmt = stmt.order_by(cursor_rowid_column)
|
|
@@ -9,7 +9,7 @@ from strawberry.relay.types import Connection, Edge, NodeType, PageInfo
|
|
|
9
9
|
from typing_extensions import TypeAlias, assert_never
|
|
10
10
|
|
|
11
11
|
ID: TypeAlias = int
|
|
12
|
-
CursorSortColumnValue: TypeAlias = Union[str, int, float, datetime]
|
|
12
|
+
CursorSortColumnValue: TypeAlias = Union[str, int, float, datetime, None]
|
|
13
13
|
|
|
14
14
|
# A type alias for the connection cursor implementation
|
|
15
15
|
CursorString = str
|
|
@@ -19,6 +19,7 @@ CURSOR_PREFIX = "connection:"
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class CursorSortColumnDataType(Enum):
|
|
22
|
+
NULL = auto()
|
|
22
23
|
STRING = auto()
|
|
23
24
|
INT = auto()
|
|
24
25
|
FLOAT = auto()
|
|
@@ -30,6 +31,10 @@ class CursorSortColumn:
|
|
|
30
31
|
type: CursorSortColumnDataType
|
|
31
32
|
value: CursorSortColumnValue
|
|
32
33
|
|
|
34
|
+
def __post_init__(self) -> None:
|
|
35
|
+
if self.value is None:
|
|
36
|
+
self.type = CursorSortColumnDataType.NULL
|
|
37
|
+
|
|
33
38
|
def __str__(self) -> str:
|
|
34
39
|
if isinstance(self.value, str):
|
|
35
40
|
return self.value
|
|
@@ -37,7 +42,9 @@ class CursorSortColumn:
|
|
|
37
42
|
return str(self.value)
|
|
38
43
|
if isinstance(self.value, datetime):
|
|
39
44
|
return self.value.isoformat()
|
|
40
|
-
|
|
45
|
+
if self.value is None:
|
|
46
|
+
return ""
|
|
47
|
+
assert_never(self.value)
|
|
41
48
|
|
|
42
49
|
@classmethod
|
|
43
50
|
def from_string(cls, type: CursorSortColumnDataType, cursor_string: str) -> "CursorSortColumn":
|
|
@@ -50,6 +57,8 @@ class CursorSortColumn:
|
|
|
50
57
|
value = float(cursor_string)
|
|
51
58
|
elif type is CursorSortColumnDataType.DATETIME:
|
|
52
59
|
value = datetime.fromisoformat(cursor_string)
|
|
60
|
+
elif type is CursorSortColumnDataType.NULL:
|
|
61
|
+
value = None
|
|
53
62
|
else:
|
|
54
63
|
assert_never(type)
|
|
55
64
|
return cls(type=type, value=value)
|