arize-phoenix 11.8.0__py3-none-any.whl → 11.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-11.8.0.dist-info → arize_phoenix-11.9.0.dist-info}/METADATA +1 -1
- {arize_phoenix-11.8.0.dist-info → arize_phoenix-11.9.0.dist-info}/RECORD +24 -23
- phoenix/db/insertion/span.py +12 -10
- phoenix/db/insertion/types.py +9 -2
- phoenix/server/api/input_types/CreateProjectInput.py +27 -0
- phoenix/server/api/mutations/project_mutations.py +37 -1
- phoenix/server/api/mutations/trace_mutations.py +45 -1
- phoenix/server/api/types/Project.py +554 -0
- phoenix/server/cost_tracking/model_cost_manifest.json +85 -0
- phoenix/server/dml_event.py +4 -0
- phoenix/server/static/.vite/manifest.json +36 -36
- phoenix/server/static/assets/{components-5M9nebi4.js → components-IBd-PDxA.js} +368 -290
- phoenix/server/static/assets/{index-OU2WTnGN.js → index-B8EBC_Z5.js} +8 -2
- phoenix/server/static/assets/{pages-DF8rqxJ4.js → pages-6D1duYIe.js} +558 -435
- phoenix/server/static/assets/vendor-BzZ0oklU.js +939 -0
- phoenix/server/static/assets/vendor-arizeai-CvjUqTrl.js +168 -0
- phoenix/server/static/assets/{vendor-codemirror-vlcH1_iR.js → vendor-codemirror-CKK25Gd7.js} +1 -1
- phoenix/server/static/assets/vendor-recharts-CWtaRhQC.js +37 -0
- phoenix/server/static/assets/{vendor-shiki-BsknB7bv.js → vendor-shiki-D30GF-p9.js} +1 -1
- phoenix/version.py +1 -1
- phoenix/server/static/assets/vendor-Bl7CyFDw.js +0 -911
- phoenix/server/static/assets/vendor-arizeai-B_viEUUA.js +0 -180
- phoenix/server/static/assets/vendor-recharts-C9cQu72o.js +0 -59
- {arize_phoenix-11.8.0.dist-info → arize_phoenix-11.9.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-11.8.0.dist-info → arize_phoenix-11.9.0.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-11.8.0.dist-info → arize_phoenix-11.9.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-11.8.0.dist-info → arize_phoenix-11.9.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=SXY1e-dnGDUvRtF27y_ABoyLFsY29JXPVQsa1fJZTDU,23
|
|
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
|
|
@@ -30,10 +30,10 @@ phoenix/db/insertion/dataset.py,sha256=KeUtfSnznmkDDlGs6KM5URduZtIo8I951tybamwoL
|
|
|
30
30
|
phoenix/db/insertion/document_annotation.py,sha256=46IHWgILlIIoCkzgEtZIubqfpgF9KVA8ETWeblcpff0,6544
|
|
31
31
|
phoenix/db/insertion/evaluation.py,sha256=XIlDQMx9FFu_hO1TEao8_ScgKETw61AoeGezsmngXrY,6876
|
|
32
32
|
phoenix/db/insertion/helpers.py,sha256=wA4f_B8DI1pfNvX7R5luG1MklwX6rtCrvv_SOcjtJGo,4106
|
|
33
|
-
phoenix/db/insertion/span.py,sha256=
|
|
33
|
+
phoenix/db/insertion/span.py,sha256=UB4UR8QlkJdVzbJ7_-S6FXIHYjyKZSOEVzCOvwGw7cY,8414
|
|
34
34
|
phoenix/db/insertion/span_annotation.py,sha256=7m0kaOkdHhLTqs_E9Kt8BeCiHUpaU3mspm5ZdMz3lio,5728
|
|
35
35
|
phoenix/db/insertion/trace_annotation.py,sha256=Qijh7eROXLjV6OLIuKwsrc2OB9A7JnefzP4eZxlPRlc,5768
|
|
36
|
-
phoenix/db/insertion/types.py,sha256=
|
|
36
|
+
phoenix/db/insertion/types.py,sha256=T9WjPxqt7N3AuZ9WA53WT85jmFmPaHcJ98wdPxByISo,8760
|
|
37
37
|
phoenix/db/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
38
|
phoenix/db/migrations/env.py,sha256=tFO3ceuCx9Es5_2w_BXclaQMmNQKNX21b1UEV5mYdeo,3387
|
|
39
39
|
phoenix/db/migrations/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
|
|
@@ -94,7 +94,7 @@ phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
94
94
|
phoenix/server/app.py,sha256=tB00x9r0PcCLYkvOtTQ7LqdSyw7jqy8OY5e7UVYl5UE,46951
|
|
95
95
|
phoenix/server/authorization.py,sha256=OxROn7ibpKtCTrcgDkzWuNxVaQcSQ8MAx7zbjZiliK0,3201
|
|
96
96
|
phoenix/server/bearer_auth.py,sha256=f4v4W94KyTdGGCPsK1tXOe0vouPuvanAEa03XSdCvPE,6650
|
|
97
|
-
phoenix/server/dml_event.py,sha256=
|
|
97
|
+
phoenix/server/dml_event.py,sha256=8UciN7W8X_IqQfAnAeAh68BezNmfxSxuTeD6IUerTW8,2911
|
|
98
98
|
phoenix/server/dml_event_handler.py,sha256=gkDIONyTz9sLbSA6qOZCigiO5val-fvVcLzDrWNcVcg,8306
|
|
99
99
|
phoenix/server/grpc_server.py,sha256=ahHC394gFZYM3h4FmjQxZwL-a4x3mWmV2EdXYFlNEC8,4676
|
|
100
100
|
phoenix/server/jwt_store.py,sha256=B6uVildN_dQDTG_-aHHvuVSI7wIVK1yvED-_y6se2GU,16905
|
|
@@ -193,6 +193,7 @@ phoenix/server/api/input_types/ClearProjectInput.py,sha256=cpPFRyQ3ffy2dLbCZgYpw
|
|
|
193
193
|
phoenix/server/api/input_types/ClusterInput.py,sha256=AfhuYYHlYgdMO6Ap8cLXqAp70S0Wutx-RTzZYetN62A,173
|
|
194
194
|
phoenix/server/api/input_types/Coordinates.py,sha256=meTwbIjwTfqx5DGD2DBlH9wQzdQVNM5a8x9dp1FfIgA,173
|
|
195
195
|
phoenix/server/api/input_types/CreateDatasetInput.py,sha256=Q3MwouIx9jTQBRWDju75iMQXEGJCrL4aD4ESQp771nc,248
|
|
196
|
+
phoenix/server/api/input_types/CreateProjectInput.py,sha256=ySfMzilUl5H0WAxcbn1rN-AlElbQGOgKT2-oY4JtnfY,866
|
|
196
197
|
phoenix/server/api/input_types/CreateSpanAnnotationInput.py,sha256=BtPB8udqnpK7kQxPpryxoO4D4yoN1E4qYF2VZxqw2LQ,706
|
|
197
198
|
phoenix/server/api/input_types/CreateTraceAnnotationInput.py,sha256=GBzOwRw_GNQq3RwS5kDp32j55VI1czOmvEmRESqCsRQ,625
|
|
198
199
|
phoenix/server/api/input_types/DataQualityMetricInput.py,sha256=WPWRlqSejOnxlLqsbEwPCDgz8ocsyGSb-9SptdCjZEc,1361
|
|
@@ -235,14 +236,14 @@ phoenix/server/api/mutations/dataset_mutations.py,sha256=KRlF-Ag3twqaBpLR_6WYxf5
|
|
|
235
236
|
phoenix/server/api/mutations/experiment_mutations.py,sha256=p3CoLAa8nFPa3D759Y2A7De_PVJNGOL98mA3HoZBrRQ,3188
|
|
236
237
|
phoenix/server/api/mutations/export_events_mutations.py,sha256=xoDnVWC7eA_8wNQP0-oyiHojyUZ0EhVVSrsAnztetC0,3993
|
|
237
238
|
phoenix/server/api/mutations/model_mutations.py,sha256=eh-QIKww3EDrDewS3NTWTqnE2bwLJJ5WgRFvSPRksZg,7199
|
|
238
|
-
phoenix/server/api/mutations/project_mutations.py,sha256=
|
|
239
|
+
phoenix/server/api/mutations/project_mutations.py,sha256=PQCwODI0VXk9Rllxdar4bNEyaYb1rJiMHXTqol-cFYY,4569
|
|
239
240
|
phoenix/server/api/mutations/project_trace_retention_policy_mutations.py,sha256=AqBe8TBxlXdIL56Afs4FIBqkI0bEgf-v9bHlbc-O6VI,9839
|
|
240
241
|
phoenix/server/api/mutations/prompt_label_mutations.py,sha256=uCiVcULtmgaNaav4M08ipPYM68sZv1MVLrCgvW-Xyn8,7317
|
|
241
242
|
phoenix/server/api/mutations/prompt_mutations.py,sha256=Yg-6L2PiKUZfFyNarptu3OdE0uA2_Nyl3VrLVP8FJ9Y,12114
|
|
242
243
|
phoenix/server/api/mutations/prompt_version_tag_mutations.py,sha256=t77osYb5he2Am4UeNis7pzY9MnaA9PNEQhsQelRH8k8,5767
|
|
243
244
|
phoenix/server/api/mutations/span_annotations_mutations.py,sha256=LQPcODp7-ZobXspjmtLaamyQa8UkTONC_va-ST9r-k8,15015
|
|
244
245
|
phoenix/server/api/mutations/trace_annotations_mutations.py,sha256=PLNNzSlk3fyJHkAVaMGR8pbWB63nOos-cStUWbTi7f8,11995
|
|
245
|
-
phoenix/server/api/mutations/trace_mutations.py,sha256=
|
|
246
|
+
phoenix/server/api/mutations/trace_mutations.py,sha256=AvtQAfqNWBQpJOZm4e0DZFimhVJ6HQHtSSZtezRadCo,4698
|
|
246
247
|
phoenix/server/api/mutations/user_mutations.py,sha256=pNQ7nyOnqBsm5pAQALdvsEaGM889JQTKg0kBv_-YyYs,15393
|
|
247
248
|
phoenix/server/api/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
248
249
|
phoenix/server/api/openapi/main.py,sha256=yKdzJYI4cxy_1mFcK4_7YObIcuRviBIfwNjB23RG14k,461
|
|
@@ -319,7 +320,7 @@ phoenix/server/api/types/ModelInterface.py,sha256=Qe7H23wDb_Q2-HmeY2t0R5Jsn4aAfY
|
|
|
319
320
|
phoenix/server/api/types/NumericRange.py,sha256=afEjgF97Go_OvmjMggbPBt-zGM8IONewAyEiKEHRds0,192
|
|
320
321
|
phoenix/server/api/types/PerformanceMetric.py,sha256=KFkmJDqP43eDUtARQOUqR7NYcxvL6Vh2uisHWU6H3ko,387
|
|
321
322
|
phoenix/server/api/types/PlaygroundModel.py,sha256=IqJFxsAAJMRyaFI9ryI3GQrpFOJ5Llf6kIutEO-tFvM,321
|
|
322
|
-
phoenix/server/api/types/Project.py,sha256=
|
|
323
|
+
phoenix/server/api/types/Project.py,sha256=gtKuIrKZXN4oP5tfY403zAnyv6yKOJ4TEG89MXZw1XY,63039
|
|
323
324
|
phoenix/server/api/types/ProjectSession.py,sha256=uwqTsDTfSGz13AvP-cwS_mJR5JZ1lHqu10ungbl7g5s,6245
|
|
324
325
|
phoenix/server/api/types/ProjectTraceRetentionPolicy.py,sha256=tYy2kgalPDyuaYZr0VUHjH0YpXaiF_QOzg5yfaV_c7c,3782
|
|
325
326
|
phoenix/server/api/types/Prompt.py,sha256=ccP4eq1e38xbF0afclGWLOuDpBVpNbJ3AOSRClF8yFQ,4955
|
|
@@ -359,7 +360,7 @@ phoenix/server/cost_tracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
|
359
360
|
phoenix/server/cost_tracking/cost_details_calculator.py,sha256=Tt0YcuLhgPuXKWJemWVmYQfG0xQUvH4VziIj6KcDnoA,8945
|
|
360
361
|
phoenix/server/cost_tracking/cost_model_lookup.py,sha256=jhtVdnQBzrTUHeOGPWgOebk-Io5hpJ1vAgWOu8ojeJ4,6801
|
|
361
362
|
phoenix/server/cost_tracking/helpers.py,sha256=Pk6ECjnYreTxrldtRwxnwFcxIPVsvDq_yAwDA_spkOc,2122
|
|
362
|
-
phoenix/server/cost_tracking/model_cost_manifest.json,sha256=
|
|
363
|
+
phoenix/server/cost_tracking/model_cost_manifest.json,sha256=aIprOWjHWUz0nrkDHII5dDybGi5prD-_xa3IGC-e838,55889
|
|
363
364
|
phoenix/server/cost_tracking/regex_specificity.py,sha256=9kqWuQ68C-hlwW25hr7BhFlRt5y2Nnpy0Ax3n9UN6Xk,11622
|
|
364
365
|
phoenix/server/cost_tracking/token_cost_calculator.py,sha256=2JEZnvusx2-xbhp8krp9EarjWuyGH2KO4e-ZwJX-K0s,1598
|
|
365
366
|
phoenix/server/daemons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -386,16 +387,16 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
|
|
|
386
387
|
phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
|
|
387
388
|
phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
|
|
388
389
|
phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
|
|
389
|
-
phoenix/server/static/.vite/manifest.json,sha256=
|
|
390
|
-
phoenix/server/static/assets/components-
|
|
391
|
-
phoenix/server/static/assets/index-
|
|
392
|
-
phoenix/server/static/assets/pages-
|
|
393
|
-
phoenix/server/static/assets/vendor-
|
|
390
|
+
phoenix/server/static/.vite/manifest.json,sha256=QXaZIXfZ1XJbL6ZbmTvaV7nhgFrHNPHk39Z6-KJ2CvU,2165
|
|
391
|
+
phoenix/server/static/assets/components-IBd-PDxA.js,sha256=kymjnoRdLP2OwD5Vj2ceDzClon_jY_9ehCAB4umjzPw,620385
|
|
392
|
+
phoenix/server/static/assets/index-B8EBC_Z5.js,sha256=GIGSeOxAeTTcPl9CydKaWjtEcTxIAlofTEf8Y7olppo,62006
|
|
393
|
+
phoenix/server/static/assets/pages-6D1duYIe.js,sha256=9IoSD0ulNxPRDTQTkKg8AVylMlOPCOMbVkJPCEHOWjg,1173753
|
|
394
|
+
phoenix/server/static/assets/vendor-BzZ0oklU.js,sha256=hZdQcaVySUPWh4GXRhuL-PhUy2K4sJLs6gYxde6qB_I,2748936
|
|
394
395
|
phoenix/server/static/assets/vendor-WIZid84E.css,sha256=spZD2r7XL5GfLO13ln-IuXfnjAref8l6g_n_AvxxOlI,5517
|
|
395
|
-
phoenix/server/static/assets/vendor-arizeai-
|
|
396
|
-
phoenix/server/static/assets/vendor-codemirror-
|
|
397
|
-
phoenix/server/static/assets/vendor-recharts-
|
|
398
|
-
phoenix/server/static/assets/vendor-shiki-
|
|
396
|
+
phoenix/server/static/assets/vendor-arizeai-CvjUqTrl.js,sha256=Db8aE6L0fWXbql2WfogS6GR0xM-uMYbdxT0zkQlUBAc,151750
|
|
397
|
+
phoenix/server/static/assets/vendor-codemirror-CKK25Gd7.js,sha256=SlvwAdf_42ZJzqkhPA-sl18TtA8CvBc3KWU5oeakfWw,781264
|
|
398
|
+
phoenix/server/static/assets/vendor-recharts-CWtaRhQC.js,sha256=KYjaE5frWsva6vjzSpMLXt_Af2eJ__67hLvazywljcQ,231651
|
|
399
|
+
phoenix/server/static/assets/vendor-shiki-D30GF-p9.js,sha256=zmvCVHLZ-XkVKFmo5ZLIWxvvcjFBpB4bza9ElUVNLxE,8980312
|
|
399
400
|
phoenix/server/static/assets/vendor-three-C5WAXd5r.js,sha256=ELkg06u70N7h8oFmvqdoHyPuUf9VgGEWeT4LKFx4VWo,620975
|
|
400
401
|
phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
401
402
|
phoenix/server/templates/index.html,sha256=rTdJZOlbZmm1dMCrHWikAwcecZDxduPU5zCFd2h2cbs,6819
|
|
@@ -436,9 +437,9 @@ phoenix/utilities/project.py,sha256=auVpARXkDb-JgeX5f2aStyFIkeKvGwN9l7qrFeJMVxI,
|
|
|
436
437
|
phoenix/utilities/re.py,sha256=6YyUWIkv0zc2SigsxfOWIHzdpjKA_TZo2iqKq7zJKvw,2081
|
|
437
438
|
phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
438
439
|
phoenix/utilities/template_formatters.py,sha256=gh9PJD6WEGw7TEYXfSst1UR4pWWwmjxMLrDVQ_CkpkQ,2779
|
|
439
|
-
arize_phoenix-11.
|
|
440
|
-
arize_phoenix-11.
|
|
441
|
-
arize_phoenix-11.
|
|
442
|
-
arize_phoenix-11.
|
|
443
|
-
arize_phoenix-11.
|
|
444
|
-
arize_phoenix-11.
|
|
440
|
+
arize_phoenix-11.9.0.dist-info/METADATA,sha256=KNs35sXwK0WNwDhesRYOlxn7itnyOf3XwlKfj5b2G3o,30850
|
|
441
|
+
arize_phoenix-11.9.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
442
|
+
arize_phoenix-11.9.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
|
|
443
|
+
arize_phoenix-11.9.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
|
|
444
|
+
arize_phoenix-11.9.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
|
|
445
|
+
arize_phoenix-11.9.0.dist-info/RECORD,,
|
phoenix/db/insertion/span.py
CHANGED
|
@@ -28,15 +28,6 @@ async def insert_span(
|
|
|
28
28
|
project_name: str,
|
|
29
29
|
) -> Optional[SpanInsertionEvent]:
|
|
30
30
|
dialect = SupportedSQLDialect(session.bind.dialect.name)
|
|
31
|
-
if (
|
|
32
|
-
project_rowid := await session.scalar(
|
|
33
|
-
select(models.Project.id).filter_by(name=project_name)
|
|
34
|
-
)
|
|
35
|
-
) is None:
|
|
36
|
-
project_rowid = await session.scalar(
|
|
37
|
-
insert(models.Project).values(name=project_name).returning(models.Project.id)
|
|
38
|
-
)
|
|
39
|
-
assert project_rowid is not None
|
|
40
31
|
|
|
41
32
|
trace_id = span.context.trace_id
|
|
42
33
|
trace: models.Trace = await session.scalar(
|
|
@@ -44,16 +35,27 @@ async def insert_span(
|
|
|
44
35
|
) or models.Trace(trace_id=trace_id)
|
|
45
36
|
|
|
46
37
|
if trace.id is not None:
|
|
38
|
+
# We use the existing project_rowid on the trace because we allow users to transfer traces
|
|
39
|
+
# between projects, so the project_name parameter is ignored for existing traces.
|
|
40
|
+
project_rowid = trace.project_rowid
|
|
47
41
|
# Trace record may need to be updated.
|
|
48
42
|
if trace.end_time < span.end_time:
|
|
49
43
|
trace.end_time = span.end_time
|
|
50
|
-
trace.project_rowid = project_rowid
|
|
51
44
|
if span.start_time < trace.start_time:
|
|
52
45
|
trace.start_time = span.start_time
|
|
53
46
|
else:
|
|
54
47
|
# Trace record needs to be persisted for the first time.
|
|
55
48
|
trace.start_time = span.start_time
|
|
56
49
|
trace.end_time = span.end_time
|
|
50
|
+
if (
|
|
51
|
+
project_rowid := await session.scalar(
|
|
52
|
+
select(models.Project.id).filter_by(name=project_name)
|
|
53
|
+
)
|
|
54
|
+
) is None:
|
|
55
|
+
project_rowid = await session.scalar(
|
|
56
|
+
insert(models.Project).values(name=project_name).returning(models.Project.id)
|
|
57
|
+
)
|
|
58
|
+
assert project_rowid is not None
|
|
57
59
|
trace.project_rowid = project_rowid
|
|
58
60
|
session.add(trace)
|
|
59
61
|
|
phoenix/db/insertion/types.py
CHANGED
|
@@ -94,7 +94,10 @@ class QueueInserter(ABC, Generic[_PrecursorT, _InsertableT, _RowT, _DmlEventT]):
|
|
|
94
94
|
async def insert(self) -> Optional[list[_DmlEventT]]:
|
|
95
95
|
if not self._queue:
|
|
96
96
|
return None
|
|
97
|
-
|
|
97
|
+
parcels = self._queue.copy()
|
|
98
|
+
# IMPORTANT: Use .clear() instead of reassignment, i.e. self._queue = [], to
|
|
99
|
+
# avoid potential race conditions when appending postponed items to the queue.
|
|
100
|
+
self._queue.clear()
|
|
98
101
|
events: list[_DmlEventT] = []
|
|
99
102
|
async with self._db() as session:
|
|
100
103
|
to_insert, to_postpone, _ = await self._partition(session, *parcels)
|
|
@@ -104,9 +107,13 @@ class QueueInserter(ABC, Generic[_PrecursorT, _InsertableT, _RowT, _DmlEventT]):
|
|
|
104
107
|
to_postpone.extend(to_retry)
|
|
105
108
|
if to_postpone:
|
|
106
109
|
loop = asyncio.get_running_loop()
|
|
107
|
-
loop.call_later(self._retry_delay_sec, self.
|
|
110
|
+
loop.call_later(self._retry_delay_sec, self._add_postponed_to_queue, to_postpone)
|
|
108
111
|
return events
|
|
109
112
|
|
|
113
|
+
def _add_postponed_to_queue(self, items: list[Postponed[_PrecursorT]]) -> None:
|
|
114
|
+
"""Add postponed items back to the queue for retry."""
|
|
115
|
+
self._queue.extend(items)
|
|
116
|
+
|
|
110
117
|
def _insert_on_conflict(self, *records: Mapping[str, Any]) -> Insert:
|
|
111
118
|
return insert_on_conflict(
|
|
112
119
|
*records,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import strawberry
|
|
5
|
+
from strawberry import UNSET
|
|
6
|
+
|
|
7
|
+
from phoenix.server.api.exceptions import BadRequest
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@strawberry.input
|
|
11
|
+
class CreateProjectInput:
|
|
12
|
+
name: str
|
|
13
|
+
description: Optional[str] = UNSET
|
|
14
|
+
gradient_start_color: Optional[str] = UNSET
|
|
15
|
+
gradient_end_color: Optional[str] = UNSET
|
|
16
|
+
|
|
17
|
+
def __post_init__(self) -> None:
|
|
18
|
+
if not self.name.strip():
|
|
19
|
+
raise BadRequest("Name cannot be empty")
|
|
20
|
+
if self.gradient_start_color and not re.match(
|
|
21
|
+
r"^#([0-9a-fA-F]{6})$", self.gradient_start_color
|
|
22
|
+
):
|
|
23
|
+
raise BadRequest("Gradient start color must be a valid hex color")
|
|
24
|
+
if self.gradient_end_color and not re.match(
|
|
25
|
+
r"^#([0-9a-fA-F]{6})$", self.gradient_end_color
|
|
26
|
+
):
|
|
27
|
+
raise BadRequest("Gradient end color must be a valid hex color")
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import strawberry
|
|
2
2
|
from sqlalchemy import delete, select
|
|
3
|
+
from sqlalchemy.exc import IntegrityError as PostgreSQLIntegrityError
|
|
3
4
|
from sqlalchemy.orm import load_only
|
|
5
|
+
from sqlean.dbapi2 import IntegrityError as SQLiteIntegrityError # type: ignore[import-untyped]
|
|
4
6
|
from strawberry.relay import GlobalID
|
|
5
7
|
from strawberry.types import Info
|
|
6
8
|
|
|
@@ -8,14 +10,48 @@ from phoenix.config import DEFAULT_PROJECT_NAME
|
|
|
8
10
|
from phoenix.db import models
|
|
9
11
|
from phoenix.server.api.auth import IsNotReadOnly
|
|
10
12
|
from phoenix.server.api.context import Context
|
|
13
|
+
from phoenix.server.api.exceptions import BadRequest, Conflict
|
|
11
14
|
from phoenix.server.api.input_types.ClearProjectInput import ClearProjectInput
|
|
15
|
+
from phoenix.server.api.input_types.CreateProjectInput import CreateProjectInput
|
|
12
16
|
from phoenix.server.api.queries import Query
|
|
13
17
|
from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
14
|
-
from phoenix.server.
|
|
18
|
+
from phoenix.server.api.types.Project import Project, to_gql_project
|
|
19
|
+
from phoenix.server.dml_event import ProjectDeleteEvent, ProjectInsertEvent, SpanDeleteEvent
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@strawberry.type
|
|
23
|
+
class ProjectMutationPayload:
|
|
24
|
+
project: Project
|
|
25
|
+
query: Query
|
|
15
26
|
|
|
16
27
|
|
|
17
28
|
@strawberry.type
|
|
18
29
|
class ProjectMutationMixin:
|
|
30
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
31
|
+
async def create_project(
|
|
32
|
+
self,
|
|
33
|
+
info: Info[Context, None],
|
|
34
|
+
input: CreateProjectInput,
|
|
35
|
+
) -> ProjectMutationPayload:
|
|
36
|
+
if not (name := input.name.strip()):
|
|
37
|
+
raise BadRequest("Name cannot be empty")
|
|
38
|
+
description = (input.description or "").strip() or None
|
|
39
|
+
gradient_start_color = (input.gradient_start_color or "").strip() or None
|
|
40
|
+
gradient_end_color = (input.gradient_end_color or "").strip() or None
|
|
41
|
+
project = models.Project(
|
|
42
|
+
name=name,
|
|
43
|
+
description=description,
|
|
44
|
+
gradient_start_color=gradient_start_color,
|
|
45
|
+
gradient_end_color=gradient_end_color,
|
|
46
|
+
)
|
|
47
|
+
try:
|
|
48
|
+
async with info.context.db() as session:
|
|
49
|
+
session.add(project)
|
|
50
|
+
except (PostgreSQLIntegrityError, SQLiteIntegrityError):
|
|
51
|
+
raise Conflict(f"Project with name '{name}' already exists")
|
|
52
|
+
info.context.event_queue.put(ProjectInsertEvent((project.id,)))
|
|
53
|
+
return ProjectMutationPayload(project=to_gql_project(project), query=Query())
|
|
54
|
+
|
|
19
55
|
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
20
56
|
async def delete_project(self, info: Info[Context, None], id: GlobalID) -> Query:
|
|
21
57
|
project_id = from_global_id_with_expected_type(global_id=id, expected_type_name="Project")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import strawberry
|
|
2
|
-
from sqlalchemy import and_, delete, not_, select
|
|
2
|
+
from sqlalchemy import and_, delete, not_, select, update
|
|
3
3
|
from sqlalchemy.orm import load_only
|
|
4
4
|
from sqlalchemy.sql import literal
|
|
5
5
|
from strawberry.relay import GlobalID
|
|
@@ -72,3 +72,47 @@ class TraceMutationMixin:
|
|
|
72
72
|
)
|
|
73
73
|
info.context.event_queue.put(SpanDeleteEvent(project_ids))
|
|
74
74
|
return Query()
|
|
75
|
+
|
|
76
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
77
|
+
async def transfer_traces_to_project(
|
|
78
|
+
self,
|
|
79
|
+
info: Info[Context, None],
|
|
80
|
+
trace_ids: list[GlobalID],
|
|
81
|
+
project_id: GlobalID,
|
|
82
|
+
) -> Query:
|
|
83
|
+
if not trace_ids:
|
|
84
|
+
raise BadRequest("Must provide at least one trace ID to transfer")
|
|
85
|
+
trace_ids = list(set(trace_ids))
|
|
86
|
+
try:
|
|
87
|
+
trace_rowids = [
|
|
88
|
+
from_global_id_with_expected_type(global_id=id, expected_type_name="Trace")
|
|
89
|
+
for id in trace_ids
|
|
90
|
+
]
|
|
91
|
+
dest_project_rowid = from_global_id_with_expected_type(
|
|
92
|
+
global_id=project_id, expected_type_name="Project"
|
|
93
|
+
)
|
|
94
|
+
except ValueError as error:
|
|
95
|
+
raise BadRequest(str(error))
|
|
96
|
+
|
|
97
|
+
async with info.context.db() as session:
|
|
98
|
+
dest_project = await session.get(models.Project, dest_project_rowid)
|
|
99
|
+
if dest_project is None:
|
|
100
|
+
raise BadRequest("Destination project does not exist")
|
|
101
|
+
|
|
102
|
+
traces = (
|
|
103
|
+
await session.scalars(select(models.Trace).where(models.Trace.id.in_(trace_rowids)))
|
|
104
|
+
).all()
|
|
105
|
+
if len(traces) < len(trace_rowids):
|
|
106
|
+
raise BadRequest("Invalid trace IDs provided")
|
|
107
|
+
|
|
108
|
+
source_project_ids = set(trace.project_rowid for trace in traces)
|
|
109
|
+
if len(source_project_ids) > 1:
|
|
110
|
+
raise BadRequest("Cannot transfer traces from multiple projects")
|
|
111
|
+
|
|
112
|
+
await session.execute(
|
|
113
|
+
update(models.Trace)
|
|
114
|
+
.where(models.Trace.id.in_(trace_rowids))
|
|
115
|
+
.values(project_rowid=dest_project_rowid)
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return Query()
|