arize-phoenix 10.2.1__py3-none-any.whl → 10.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arize-phoenix might be problematic. Click here for more details.
- {arize_phoenix-10.2.1.dist-info → arize_phoenix-10.3.0.dist-info}/METADATA +8 -1
- {arize_phoenix-10.2.1.dist-info → arize_phoenix-10.3.0.dist-info}/RECORD +26 -25
- phoenix/db/enums.py +3 -12
- phoenix/db/facilitator.py +25 -33
- phoenix/db/models.py +6 -1
- phoenix/db/types/trace_retention.py +17 -10
- phoenix/server/api/mutations/api_key_mutations.py +5 -4
- phoenix/server/api/mutations/user_mutations.py +3 -11
- phoenix/server/api/queries.py +5 -5
- phoenix/server/api/routers/oauth2.py +1 -4
- phoenix/server/api/routers/v1/__init__.py +2 -0
- phoenix/server/api/routers/v1/models.py +7 -0
- phoenix/server/api/routers/v1/projects.py +2 -3
- phoenix/server/api/routers/v1/users.py +346 -0
- phoenix/server/bearer_auth.py +3 -4
- phoenix/server/jwt_store.py +9 -9
- phoenix/server/static/.vite/manifest.json +9 -9
- phoenix/server/static/assets/{components-ClD3sHta.js → components-DVEsaeYg.js} +2 -2
- phoenix/server/static/assets/{index-CXawXHw0.js → index-cY-swWDK.js} +2 -2
- phoenix/server/static/assets/{pages-BFtNRfTL.js → pages-xeDsefDx.js} +389 -389
- phoenix/server/types.py +3 -2
- phoenix/version.py +1 -1
- {arize_phoenix-10.2.1.dist-info → arize_phoenix-10.3.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-10.2.1.dist-info → arize_phoenix-10.3.0.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-10.2.1.dist-info → arize_phoenix-10.3.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-10.2.1.dist-info → arize_phoenix-10.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arize-phoenix
|
|
3
|
-
Version: 10.
|
|
3
|
+
Version: 10.3.0
|
|
4
4
|
Summary: AI Observability and Evaluation
|
|
5
5
|
Project-URL: Documentation, https://docs.arize.com/phoenix/
|
|
6
6
|
Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
|
|
@@ -158,6 +158,9 @@ Description-Content-Type: text/markdown
|
|
|
158
158
|
<a target="_blank" href="https://hub.docker.com/r/arizephoenix/phoenix/tags">
|
|
159
159
|
<img src="https://img.shields.io/docker/v/arizephoenix/phoenix?sort=semver&logo=docker&label=image&color=blue">
|
|
160
160
|
</a>
|
|
161
|
+
<a target="_blank" href="https://hub.docker.com/r/arizephoenix/phoenix-helm">
|
|
162
|
+
<img src="https://img.shields.io/badge/Helm-blue?style=flat&logo=helm&labelColor=grey"/>
|
|
163
|
+
</a>
|
|
161
164
|
<a target="_blank" href="https://github.com/Arize-ai/phoenix/tree/main/js/packages/phoenix-mcp">
|
|
162
165
|
<img src="https://badge.mcpx.dev?status=on" title="MCP Enabled"/>
|
|
163
166
|
</a>
|
|
@@ -226,6 +229,9 @@ Phoenix is built on top of OpenTelemetry and is vendor, language, and framework
|
|
|
226
229
|
| [Smolagents](https://huggingface.co/docs/smolagents/en/tutorials/inspect_runs) | `openinference-instrumentation-smolagents` | [](https://pypi.python.org/pypi/openinference-instrumentation-smolagents) |
|
|
227
230
|
| [Agno](https://docs.arize.com/phoenix/tracing/integrations-tracing/agno) | `openinference-instrumentation-agno` | [](https://pypi.python.org/pypi/openinference-instrumentation-agno) |
|
|
228
231
|
| [MCP](https://docs.arize.com/phoenix/tracing/integrations-tracing/model-context-protocol-mcp) | `openinference-instrumentation-mcp` | [](https://pypi.python.org/pypi/openinference-instrumentation-mcp) |
|
|
232
|
+
| [Pydantic AI](https://docs.arize.com/phoenix/integrations/pydantic) | `openinference-instrumentation-pydantic-ai` | [](https://pypi.python.org/pypi/openinference-instrumentation-pydantic-ai) |
|
|
233
|
+
| [Autogen AgentChat](https://docs.arize.com/phoenix/integrations/frameworks/autogen/autogen-tracing) | `openinference-instrumentation-autogen-agentchat` | [](https://pypi.python.org/pypi/openinference-instrumentation-autogen-agentchat) |
|
|
234
|
+
| [Portkey](https://docs.arize.com/phoenix/integrations/portkey) | `openinference-instrumentation-portkey` | [](https://pypi.python.org/pypi/openinference-instrumentation-portkey) |
|
|
229
235
|
|
|
230
236
|
### JavaScript Integrations
|
|
231
237
|
|
|
@@ -235,6 +241,7 @@ Phoenix is built on top of OpenTelemetry and is vendor, language, and framework
|
|
|
235
241
|
| [LangChain.js](https://docs.arize.com/phoenix/tracing/integrations-tracing/langchain.js) | `@arizeai/openinference-instrumentation-langchain` | [](https://www.npmjs.com/package/@arizeai/openinference-instrumentation-langchain) |
|
|
236
242
|
| [Vercel AI SDK](https://docs.arize.com/phoenix/tracing/integrations-tracing/vercel-ai-sdk) | `@arizeai/openinference-vercel` | [](https://www.npmjs.com/package/@arizeai/openinference-vercel) |
|
|
237
243
|
| [BeeAI](https://docs.arize.com/phoenix/tracing/integrations-tracing/beeai) | `@arizeai/openinference-instrumentation-beeai` | [](https://www.npmjs.com/package/@arizeai/openinference-instrumentation-beeai) |
|
|
244
|
+
| [Mastra](https://docs.arize.com/phoenix/integrations/mastra) | `@arizeai/openinference-mastra` | [](https://www.npmjs.com/package/@arizeai/openinference-mastra) |
|
|
238
245
|
|
|
239
246
|
### Platforms
|
|
240
247
|
|
|
@@ -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=x87BX7hWGQQZbrW_vrYqFR_izCGfO9gFc--JXUG4Tdk,754
|
|
9
|
-
phoenix/version.py,sha256=
|
|
9
|
+
phoenix/version.py,sha256=en71LMLGHaniA0cRhdCNZcZs3ADBfzRLJmhNSPLsLZs,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
|
|
@@ -18,11 +18,11 @@ phoenix/db/alembic.ini,sha256=GIS6HpHaKaJbbuahZg1Rc1D2_QqyCkV9r58wdARGf6w,3262
|
|
|
18
18
|
phoenix/db/bulk_inserter.py,sha256=faNjuwLqqsw4ky8sa4D0h9u5TvEDTOjrccUW89L008E,12725
|
|
19
19
|
phoenix/db/constants.py,sha256=-YE2rkzcROG06_rerfnX5hC7fLzOHx1Gjw4nXhX_um4,46
|
|
20
20
|
phoenix/db/engines.py,sha256=tB_8iWMDz0folryVvw29sbBUxJOB2XZ-Xx0Uexj3uns,6889
|
|
21
|
-
phoenix/db/enums.py,sha256=
|
|
22
|
-
phoenix/db/facilitator.py,sha256=
|
|
21
|
+
phoenix/db/enums.py,sha256=w3O5YuJEEzVTwVDZb8b2UUFhU8yK_GosF081VVrrno0,188
|
|
22
|
+
phoenix/db/facilitator.py,sha256=E25egiPMhuDVjH_kl1yMSO1bNWsP8Kn0IK-hXJXDD_4,9574
|
|
23
23
|
phoenix/db/helpers.py,sha256=rbbHcl-STzcEpcXCYx6jbKzko7r3ggrWHHsXjZ48HsM,5352
|
|
24
24
|
phoenix/db/migrate.py,sha256=oUrXH8yEbcpL4eh09aSCuUiSrhFli0eT5D_j4ZmYChY,2797
|
|
25
|
-
phoenix/db/models.py,sha256=
|
|
25
|
+
phoenix/db/models.py,sha256=UXUyYD4f6Cz4Zmg76jhjJmUbpTf1evC5mTc__u1l3FY,52195
|
|
26
26
|
phoenix/db/pg_config.py,sha256=h6mB7qF7t4Zk6VGvAiyefHGVu74o-yJynaWzeE39k9Y,6001
|
|
27
27
|
phoenix/db/insertion/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
28
|
phoenix/db/insertion/constants.py,sha256=8wifm7X-1XvroZ__R2Gc96NsgLhTDn0zXl4lehlXtcA,70
|
|
@@ -54,7 +54,7 @@ phoenix/db/types/annotation_configs.py,sha256=keiQ9mzLZWE8Eqsu1xFxQBXvBiym0s-yPz
|
|
|
54
54
|
phoenix/db/types/db_models.py,sha256=nMSd9gWHwObnVO3_slztlHqoeh04czS-Jxu-omS6M6E,1135
|
|
55
55
|
phoenix/db/types/identifier.py,sha256=Opr3_1di6e5ncrBDn30WfBSr-jN_VGBnkkA4BMuSoyc,244
|
|
56
56
|
phoenix/db/types/model_provider.py,sha256=M5SKYtK176SxYhZ-c5gQSiTTuDk8VeAxqM8jrGyfGTo,183
|
|
57
|
-
phoenix/db/types/trace_retention.py,sha256=
|
|
57
|
+
phoenix/db/types/trace_retention.py,sha256=fyqAQCvDiD7mpJ_WUqbPyQvuSdERof4DpKpHLJsdROk,9897
|
|
58
58
|
phoenix/experiments/__init__.py,sha256=6JGwgUd7xCbGpuHqYZlsmErmYvVgv7N_j43bn3dUqsk,123
|
|
59
59
|
phoenix/experiments/functions.py,sha256=6cSS_5O5V1EZ_5CIQ6lGOUwFyNNsADP7Uu__GmuOz4A,37983
|
|
60
60
|
phoenix/experiments/tracing.py,sha256=seNh9rBH-rtQe8_FPI_VJj1rbo3ADcP6wDvERkMoxNc,2858
|
|
@@ -91,11 +91,11 @@ phoenix/pointcloud/umap_parameters.py,sha256=db_WEPoamuWtopZx7tQfAXPnoE0MS8FkAV0
|
|
|
91
91
|
phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
92
92
|
phoenix/server/app.py,sha256=1N7OWYQ3obWhdb_Qbrg8mSuexvNk_oT1Taq8smfmMiU,41265
|
|
93
93
|
phoenix/server/authorization.py,sha256=fofeRwuoodCUB3DQYPCuAgIyeiwopXW0tkH_KZvU0Rg,1848
|
|
94
|
-
phoenix/server/bearer_auth.py,sha256=
|
|
94
|
+
phoenix/server/bearer_auth.py,sha256=b2iHV2nwvWlZJ2O_nWOzHctJ0aUrEIOygIDrO7VOCSw,6700
|
|
95
95
|
phoenix/server/dml_event.py,sha256=MjJmVEKytq75chBOSyvYDusUnEbg1pHpIjR3pZkUaJA,2838
|
|
96
96
|
phoenix/server/dml_event_handler.py,sha256=EZLXmCvx4pJrCkz29gxwKwmvmUkTtPCHw6klR-XM8qE,8258
|
|
97
97
|
phoenix/server/grpc_server.py,sha256=dod29zE_Zlir7NyLcdVM8GH3P8sy-9ykzfaBfVifyE4,4656
|
|
98
|
-
phoenix/server/jwt_store.py,sha256=
|
|
98
|
+
phoenix/server/jwt_store.py,sha256=B6uVildN_dQDTG_-aHHvuVSI7wIVK1yvED-_y6se2GU,16905
|
|
99
99
|
phoenix/server/main.py,sha256=FI7wZW8SYPvVLC6dUVpweFcHmKcLTaUxfGE0i_4lZNw,18252
|
|
100
100
|
phoenix/server/oauth2.py,sha256=GvUqZBoZ5dG-l2G1RMl1SUcN10jNAjaMXFznMSWz2Zs,3336
|
|
101
101
|
phoenix/server/prometheus.py,sha256=1KjvSfjSa2-BPjDybVMM_Kag316CsN-Zwt64YNr_snc,7825
|
|
@@ -103,14 +103,14 @@ phoenix/server/rate_limiters.py,sha256=cFc73D2NaxqNZZDbwfIDw4So-fRVOJPBtqxOZ8Qky
|
|
|
103
103
|
phoenix/server/retention.py,sha256=MQe1FWuc_NxhqgIq5q2hfFhWT8ddAmpppgI74xYEQ6c,3064
|
|
104
104
|
phoenix/server/telemetry.py,sha256=4EluDDrhdDPxAjaW6lVSbi73xkB5XeUCZWOmZGdk0hg,2755
|
|
105
105
|
phoenix/server/thread_server.py,sha256=Ea2AWreN1lwJsT2wYvGaRaiXrzBqH4kgkZpx0FO5Ocw,2144
|
|
106
|
-
phoenix/server/types.py,sha256=
|
|
106
|
+
phoenix/server/types.py,sha256=b17xahdt6uwDdUYul0xctu7TbBC65AjarlhUzOiXFNE,7443
|
|
107
107
|
phoenix/server/api/README.md,sha256=Pyq1PLPgTzXAswrfIhGXrjI3Skq8it2jTVnanT6Ba4Q,1162
|
|
108
108
|
phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
109
109
|
phoenix/server/api/auth.py,sha256=cvKH2FQLL7PasiqZMHgu9P4qchhEG7a7P9Nxy35FoIQ,1551
|
|
110
110
|
phoenix/server/api/context.py,sha256=oxNmVIIyycl22iQZjv59lU1inwlo-Povxe2Ok7t54mw,6954
|
|
111
111
|
phoenix/server/api/exceptions.py,sha256=TA0JuY2YRnj35qGuMSQ8d0ToHum9gWm9W--3fSKHrX0,1171
|
|
112
112
|
phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
|
|
113
|
-
phoenix/server/api/queries.py,sha256=
|
|
113
|
+
phoenix/server/api/queries.py,sha256=MzfCwdR2oLlZn8p0t0VMBp2-1ZFDwleKiYvtnAU9bFc,40710
|
|
114
114
|
phoenix/server/api/schema.py,sha256=fcs36xQwFF_Qe41_5cWR8wYpDvOrnbcyTeo5WNMbDsA,1702
|
|
115
115
|
phoenix/server/api/subscriptions.py,sha256=TnZhdoNHMXp1NkUVLA-eB54woll7FvxtsB2pLt1dO0w,23001
|
|
116
116
|
phoenix/server/api/utils.py,sha256=quCBRcusc6PUq9tJq7M8PgwFZp7nXgVAxtbw8feribY,833
|
|
@@ -207,7 +207,7 @@ phoenix/server/api/input_types/UserRoleInput.py,sha256=xxhFe0ITZOgRVEJbVem_W6F1I
|
|
|
207
207
|
phoenix/server/api/input_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
208
208
|
phoenix/server/api/mutations/__init__.py,sha256=fGFokUtX4J1q9yYzRtPOwRyfJNyL_8z60gaWX9IPvtM,1872
|
|
209
209
|
phoenix/server/api/mutations/annotation_config_mutations.py,sha256=i7NsQhYICcQ-I-tnFjGtVAYc8WVmMBacmRaqHWJ25t4,15433
|
|
210
|
-
phoenix/server/api/mutations/api_key_mutations.py,sha256=
|
|
210
|
+
phoenix/server/api/mutations/api_key_mutations.py,sha256=nfnRjALCaQMi_jIbEPW4G3Dn3tPnmZVU11tpBbBijGA,6242
|
|
211
211
|
phoenix/server/api/mutations/chat_mutations.py,sha256=ChRh4YbNkBgFO05CNElzqJ1hIvo7lr5Zn0lvlRs51pE,22997
|
|
212
212
|
phoenix/server/api/mutations/dataset_mutations.py,sha256=KRlF-Ag3twqaBpLR_6WYxf57DffaGuFBm-soaBPStbI,27787
|
|
213
213
|
phoenix/server/api/mutations/experiment_mutations.py,sha256=p3CoLAa8nFPa3D759Y2A7De_PVJNGOL98mA3HoZBrRQ,3188
|
|
@@ -220,16 +220,16 @@ phoenix/server/api/mutations/prompt_version_tag_mutations.py,sha256=t77osYb5he2A
|
|
|
220
220
|
phoenix/server/api/mutations/span_annotations_mutations.py,sha256=LQPcODp7-ZobXspjmtLaamyQa8UkTONC_va-ST9r-k8,15015
|
|
221
221
|
phoenix/server/api/mutations/trace_annotations_mutations.py,sha256=PLNNzSlk3fyJHkAVaMGR8pbWB63nOos-cStUWbTi7f8,11995
|
|
222
222
|
phoenix/server/api/mutations/trace_mutations.py,sha256=D5h2HYdlTo6yYZNq-O-PjaS9GeiZHxxVaOxDdh7fwjw,2957
|
|
223
|
-
phoenix/server/api/mutations/user_mutations.py,sha256=
|
|
223
|
+
phoenix/server/api/mutations/user_mutations.py,sha256=pNQ7nyOnqBsm5pAQALdvsEaGM889JQTKg0kBv_-YyYs,15393
|
|
224
224
|
phoenix/server/api/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
225
225
|
phoenix/server/api/openapi/main.py,sha256=yKdzJYI4cxy_1mFcK4_7YObIcuRviBIfwNjB23RG14k,461
|
|
226
226
|
phoenix/server/api/openapi/schema.py,sha256=WGmHWSIyJhtc5EIh_M3vlXU-EgHkFuTlyVofgS0kj1I,529
|
|
227
227
|
phoenix/server/api/routers/__init__.py,sha256=YIzHsIFOOXuCRbDkMUHx-McrANFJK5UfUn6a4BNIzmo,277
|
|
228
228
|
phoenix/server/api/routers/auth.py,sha256=bP2ptHe53BxlG10w-8ul6fYd1ZpYW3iscV3mlMlFGp8,11479
|
|
229
229
|
phoenix/server/api/routers/embeddings.py,sha256=BpZGJee0pdL0W5Rp1L0b30dEtZTgJeVqXky8LgZ0ZXw,898
|
|
230
|
-
phoenix/server/api/routers/oauth2.py,sha256=
|
|
230
|
+
phoenix/server/api/routers/oauth2.py,sha256=EUoBeh4Ix-Uwt_q_RD75xbMcdVdd0xJLDYjELdVHBTw,24051
|
|
231
231
|
phoenix/server/api/routers/utils.py,sha256=M41BoH-fl37izhRuN2aX7lWm7jOC20A_3uClv9TVUUY,583
|
|
232
|
-
phoenix/server/api/routers/v1/__init__.py,sha256=
|
|
232
|
+
phoenix/server/api/routers/v1/__init__.py,sha256=ngLMPjC7lgZxgKy_Is33KxTRnMzSqy25qTTChCVx_Mo,2696
|
|
233
233
|
phoenix/server/api/routers/v1/annotation_configs.py,sha256=rZ3yJm7m75BVegSjSHqsdqf7n26roGg7vYYiiKfWA3A,15898
|
|
234
234
|
phoenix/server/api/routers/v1/annotations.py,sha256=oeafR2tCLu-uIwM9J72gN3MX5WDhrOMU3Jqd1uIiFqg,5921
|
|
235
235
|
phoenix/server/api/routers/v1/datasets.py,sha256=Xh-M8bnCmjflmPcgv8dAG8Cek88sApuqQlvNBuSnrYc,37534
|
|
@@ -237,11 +237,12 @@ phoenix/server/api/routers/v1/evaluations.py,sha256=GFTo42aIEX0Htn0EjjoE1JZDYlvr
|
|
|
237
237
|
phoenix/server/api/routers/v1/experiment_evaluations.py,sha256=xSs004jNYsOl3eg-6Zjo2tt9TefTd7WR3twWYrsNQNk,4828
|
|
238
238
|
phoenix/server/api/routers/v1/experiment_runs.py,sha256=FreGzzprPpJ_DBHUkdUckca6EGCrnvgVpqk3CLT7wRc,7000
|
|
239
239
|
phoenix/server/api/routers/v1/experiments.py,sha256=V9_sxqLTE1MKGFu9H3FEdGKr70lYMbGZx813MGaavfQ,20430
|
|
240
|
-
phoenix/server/api/routers/v1/models.py,sha256=
|
|
241
|
-
phoenix/server/api/routers/v1/projects.py,sha256=
|
|
240
|
+
phoenix/server/api/routers/v1/models.py,sha256=p3gJN-9SWiUYTUTft4bZMsZVCBNTb4nN1Foy68eRZzQ,1997
|
|
241
|
+
phoenix/server/api/routers/v1/projects.py,sha256=LFWxHYPRZy-1EvroNylL635vU1UuDbcuRo1oD26yBnw,12551
|
|
242
242
|
phoenix/server/api/routers/v1/prompts.py,sha256=aBOUBwLDzZDIzJQkxJcR8ZKnakNJOLMwzsLKINSs1mA,26545
|
|
243
243
|
phoenix/server/api/routers/v1/spans.py,sha256=qJVN0pVgZM5cMXQoNrCwmFjKDm_7-JHKdt_KU9IDFsA,32121
|
|
244
244
|
phoenix/server/api/routers/v1/traces.py,sha256=DfzeszQvtlrVxvurJLaWJJAhkCZ4BodLwpFuBYPwN5Q,8206
|
|
245
|
+
phoenix/server/api/routers/v1/users.py,sha256=ZcW3if0L8-lUusTzET7fhlhvnmiCICDrGimzB7i3irc,11947
|
|
245
246
|
phoenix/server/api/routers/v1/utils.py,sha256=oXIOGPzPTkE0ZWUTRCoRIQQ7wTzoSwtWFaUSjlGBqts,4960
|
|
246
247
|
phoenix/server/api/types/Annotation.py,sha256=gsl8CwjIbDUbZRj4d9USwZ_w_Tkz4i7zuZh9ftV80jA,1132
|
|
247
248
|
phoenix/server/api/types/AnnotationConfig.py,sha256=TPukZUgvFC17W93Vnme21EhswasBMR-ZiuSWteiWZOU,3891
|
|
@@ -347,10 +348,10 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
|
|
|
347
348
|
phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
|
|
348
349
|
phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
|
|
349
350
|
phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
|
|
350
|
-
phoenix/server/static/.vite/manifest.json,sha256=
|
|
351
|
-
phoenix/server/static/assets/components-
|
|
352
|
-
phoenix/server/static/assets/index-
|
|
353
|
-
phoenix/server/static/assets/pages-
|
|
351
|
+
phoenix/server/static/.vite/manifest.json,sha256=Zu0EMrSyBCgG19UC9Qt39-pXYYdvVFl3bWI6-WURO-8,2165
|
|
352
|
+
phoenix/server/static/assets/components-DVEsaeYg.js,sha256=iYUgN9SKcitX5Hyy7SdRIwgCUpvlve3iL_OOp0htCmY,546485
|
|
353
|
+
phoenix/server/static/assets/index-cY-swWDK.js,sha256=bnTHNbUklGytwJqrBXNCyxweWcL_Ml6LqdvbP3ztHC4,60432
|
|
354
|
+
phoenix/server/static/assets/pages-xeDsefDx.js,sha256=BOZ44rhUYLKD9thtTjZ8Ka0vMXbqyUA4ET_sfAzCEUw,1033804
|
|
354
355
|
phoenix/server/static/assets/vendor-DOUbLVp5.js,sha256=AN12odor8w2dKOG4LokzFITR1h52TP1qnBDQl1u67Dc,2744392
|
|
355
356
|
phoenix/server/static/assets/vendor-WIZid84E.css,sha256=spZD2r7XL5GfLO13ln-IuXfnjAref8l6g_n_AvxxOlI,5517
|
|
356
357
|
phoenix/server/static/assets/vendor-arizeai-DHqMQzfV.js,sha256=zaVJbapZYf9-reZp549G232mEi7MY7yZR2cBbchRISs,193248
|
|
@@ -397,9 +398,9 @@ phoenix/utilities/project.py,sha256=auVpARXkDb-JgeX5f2aStyFIkeKvGwN9l7qrFeJMVxI,
|
|
|
397
398
|
phoenix/utilities/re.py,sha256=6YyUWIkv0zc2SigsxfOWIHzdpjKA_TZo2iqKq7zJKvw,2081
|
|
398
399
|
phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
399
400
|
phoenix/utilities/template_formatters.py,sha256=gh9PJD6WEGw7TEYXfSst1UR4pWWwmjxMLrDVQ_CkpkQ,2779
|
|
400
|
-
arize_phoenix-10.
|
|
401
|
-
arize_phoenix-10.
|
|
402
|
-
arize_phoenix-10.
|
|
403
|
-
arize_phoenix-10.
|
|
404
|
-
arize_phoenix-10.
|
|
405
|
-
arize_phoenix-10.
|
|
401
|
+
arize_phoenix-10.3.0.dist-info/METADATA,sha256=_yB8i_JXVs8tsgZ2ysGA8D4sxs5Z_6-D0egmt_2MDB8,27004
|
|
402
|
+
arize_phoenix-10.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
403
|
+
arize_phoenix-10.3.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
|
|
404
|
+
arize_phoenix-10.3.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
|
|
405
|
+
arize_phoenix-10.3.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
|
|
406
|
+
arize_phoenix-10.3.0.dist-info/RECORD,,
|
phoenix/db/enums.py
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
|
-
from collections.abc import Mapping
|
|
2
|
-
from enum import Enum
|
|
3
|
-
|
|
4
1
|
from sqlalchemy.orm import InstrumentedAttribute
|
|
5
2
|
|
|
6
3
|
from phoenix.db import models
|
|
7
4
|
|
|
8
|
-
__all__ = ["
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class UserRole(Enum):
|
|
12
|
-
SYSTEM = "SYSTEM"
|
|
13
|
-
ADMIN = "ADMIN"
|
|
14
|
-
MEMBER = "MEMBER"
|
|
5
|
+
__all__ = ["ENUM_COLUMNS"]
|
|
15
6
|
|
|
16
7
|
|
|
17
|
-
|
|
18
|
-
models.UserRole.name
|
|
8
|
+
ENUM_COLUMNS: set[InstrumentedAttribute[str]] = {
|
|
9
|
+
models.UserRole.name,
|
|
19
10
|
}
|
phoenix/db/facilitator.py
CHANGED
|
@@ -7,12 +7,7 @@ from asyncio import gather
|
|
|
7
7
|
from functools import partial
|
|
8
8
|
from typing import Optional
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
distinct,
|
|
12
|
-
exists,
|
|
13
|
-
insert,
|
|
14
|
-
select,
|
|
15
|
-
)
|
|
10
|
+
import sqlalchemy as sa
|
|
16
11
|
|
|
17
12
|
from phoenix import config
|
|
18
13
|
from phoenix.auth import (
|
|
@@ -30,7 +25,8 @@ from phoenix.config import (
|
|
|
30
25
|
)
|
|
31
26
|
from phoenix.db import models
|
|
32
27
|
from phoenix.db.constants import DEFAULT_PROJECT_TRACE_RETENTION_POLICY_ID
|
|
33
|
-
from phoenix.db.enums import
|
|
28
|
+
from phoenix.db.enums import ENUM_COLUMNS
|
|
29
|
+
from phoenix.db.models import UserRoleName
|
|
34
30
|
from phoenix.db.types.trace_retention import (
|
|
35
31
|
MaxDaysRule,
|
|
36
32
|
TraceRetentionCronExpression,
|
|
@@ -76,18 +72,17 @@ async def _ensure_enums(db: DbSessionFactory) -> None:
|
|
|
76
72
|
they will be added. If any values are present in the database but not in the enum, an error will
|
|
77
73
|
be raised. This function is idempotent: it will not add duplicate values to the database.
|
|
78
74
|
"""
|
|
79
|
-
for column
|
|
75
|
+
for column in ENUM_COLUMNS:
|
|
80
76
|
table = column.class_
|
|
77
|
+
assert isinstance(column.type, sa.Enum)
|
|
81
78
|
async with db() as session:
|
|
82
|
-
existing = set(
|
|
83
|
-
|
|
84
|
-
)
|
|
85
|
-
expected = set(e.value for e in enum)
|
|
79
|
+
existing = set(await session.scalars(sa.select(column)))
|
|
80
|
+
expected = set(column.type.enums)
|
|
86
81
|
if unexpected := existing - expected:
|
|
87
82
|
raise ValueError(f"Unexpected values in {table.name}.{column.key}: {unexpected}")
|
|
88
83
|
if not (missing := expected - existing):
|
|
89
84
|
continue
|
|
90
|
-
await session.execute(insert(table), [{column.key: v} for v in missing])
|
|
85
|
+
await session.execute(sa.insert(table), [{column.key: v} for v in missing])
|
|
91
86
|
|
|
92
87
|
|
|
93
88
|
async def _ensure_user_roles(db: DbSessionFactory) -> None:
|
|
@@ -97,21 +92,22 @@ async def _ensure_user_roles(db: DbSessionFactory) -> None:
|
|
|
97
92
|
the email "admin@localhost".
|
|
98
93
|
"""
|
|
99
94
|
async with db() as session:
|
|
100
|
-
role_ids = {
|
|
95
|
+
role_ids: dict[UserRoleName, int] = {
|
|
101
96
|
name: id_
|
|
102
97
|
async for name, id_ in await session.stream(
|
|
103
|
-
select(models.UserRole.name, models.UserRole.id)
|
|
98
|
+
sa.select(models.UserRole.name, models.UserRole.id)
|
|
104
99
|
)
|
|
105
100
|
}
|
|
106
|
-
existing_roles = [
|
|
101
|
+
existing_roles: list[UserRoleName] = [
|
|
107
102
|
name
|
|
108
103
|
async for name in await session.stream_scalars(
|
|
109
|
-
select(distinct(models.UserRole.name)).join_from(models.User, models.UserRole)
|
|
104
|
+
sa.select(sa.distinct(models.UserRole.name)).join_from(models.User, models.UserRole)
|
|
110
105
|
)
|
|
111
106
|
]
|
|
112
|
-
if (
|
|
113
|
-
|
|
114
|
-
|
|
107
|
+
if (
|
|
108
|
+
"SYSTEM" not in existing_roles
|
|
109
|
+
and (system_role_id := role_ids.get("SYSTEM")) is not None
|
|
110
|
+
):
|
|
115
111
|
system_user = models.LocalUser(
|
|
116
112
|
user_role_id=system_role_id,
|
|
117
113
|
username=DEFAULT_SYSTEM_USERNAME,
|
|
@@ -121,9 +117,7 @@ async def _ensure_user_roles(db: DbSessionFactory) -> None:
|
|
|
121
117
|
password_hash=secrets.token_bytes(DEFAULT_SECRET_LENGTH),
|
|
122
118
|
)
|
|
123
119
|
session.add(system_user)
|
|
124
|
-
if
|
|
125
|
-
admin_role_id := role_ids.get(admin_role)
|
|
126
|
-
) is not None:
|
|
120
|
+
if "ADMIN" not in existing_roles and (admin_role_id := role_ids.get("ADMIN")) is not None:
|
|
127
121
|
salt = secrets.token_bytes(DEFAULT_SECRET_LENGTH)
|
|
128
122
|
password = get_env_default_admin_initial_password()
|
|
129
123
|
compute = partial(compute_password_hash, password=password, salt=salt)
|
|
@@ -147,9 +141,9 @@ async def _get_system_user_id(db: DbSessionFactory) -> None:
|
|
|
147
141
|
"""
|
|
148
142
|
async with db() as session:
|
|
149
143
|
system_user_id = await session.scalar(
|
|
150
|
-
select(models.User.id)
|
|
144
|
+
sa.select(models.User.id)
|
|
151
145
|
.join(models.UserRole)
|
|
152
|
-
.where(models.UserRole.name ==
|
|
146
|
+
.where(models.UserRole.name == "SYSTEM")
|
|
153
147
|
.order_by(models.User.id)
|
|
154
148
|
.limit(1)
|
|
155
149
|
)
|
|
@@ -173,7 +167,7 @@ async def _ensure_admins(
|
|
|
173
167
|
async with db() as session:
|
|
174
168
|
existing_emails = set(
|
|
175
169
|
await session.scalars(
|
|
176
|
-
select(models.User.email).where(models.User.email.in_(admins.keys()))
|
|
170
|
+
sa.select(models.User.email).where(models.User.email.in_(admins.keys()))
|
|
177
171
|
)
|
|
178
172
|
)
|
|
179
173
|
admins = {
|
|
@@ -183,7 +177,7 @@ async def _ensure_admins(
|
|
|
183
177
|
return
|
|
184
178
|
existing_usernames = set(
|
|
185
179
|
await session.scalars(
|
|
186
|
-
select(models.User.username).where(models.User.username.in_(admins.values()))
|
|
180
|
+
sa.select(models.User.username).where(models.User.username.in_(admins.values()))
|
|
187
181
|
)
|
|
188
182
|
)
|
|
189
183
|
admins = {
|
|
@@ -193,9 +187,7 @@ async def _ensure_admins(
|
|
|
193
187
|
}
|
|
194
188
|
if not admins:
|
|
195
189
|
return
|
|
196
|
-
admin_role_id = await session.scalar(
|
|
197
|
-
select(models.UserRole.id).filter_by(name=UserRole.ADMIN.value)
|
|
198
|
-
)
|
|
190
|
+
admin_role_id = await session.scalar(sa.select(models.UserRole.id).filter_by(name="ADMIN"))
|
|
199
191
|
assert admin_role_id is not None, "Admin role not found in database"
|
|
200
192
|
user: models.User
|
|
201
193
|
for email, username in admins.items():
|
|
@@ -248,8 +240,8 @@ async def _ensure_default_project_trace_retention_policy(db: DbSessionFactory) -
|
|
|
248
240
|
assert DEFAULT_PROJECT_TRACE_RETENTION_POLICY_ID == 0
|
|
249
241
|
async with db() as session:
|
|
250
242
|
if await session.scalar(
|
|
251
|
-
select(
|
|
252
|
-
exists().where(
|
|
243
|
+
sa.select(
|
|
244
|
+
sa.exists().where(
|
|
253
245
|
models.ProjectTraceRetentionPolicy.id
|
|
254
246
|
== DEFAULT_PROJECT_TRACE_RETENTION_POLICY_ID
|
|
255
247
|
)
|
|
@@ -259,7 +251,7 @@ async def _ensure_default_project_trace_retention_policy(db: DbSessionFactory) -
|
|
|
259
251
|
cron_expression = TraceRetentionCronExpression(root="0 0 * * 0")
|
|
260
252
|
rule = TraceRetentionRule(root=MaxDaysRule(max_days=0))
|
|
261
253
|
await session.execute(
|
|
262
|
-
insert(models.ProjectTraceRetentionPolicy),
|
|
254
|
+
sa.insert(models.ProjectTraceRetentionPolicy),
|
|
263
255
|
[
|
|
264
256
|
{
|
|
265
257
|
"id": DEFAULT_PROJECT_TRACE_RETENTION_POLICY_ID,
|
phoenix/db/models.py
CHANGED
|
@@ -146,6 +146,7 @@ def render_values_w_union(
|
|
|
146
146
|
return compiler.process(subquery, from_linter=from_linter, **kw)
|
|
147
147
|
|
|
148
148
|
|
|
149
|
+
UserRoleName: TypeAlias = Literal["SYSTEM", "ADMIN", "MEMBER"]
|
|
149
150
|
AuthMethod: TypeAlias = Literal["LOCAL", "OAUTH2"]
|
|
150
151
|
|
|
151
152
|
|
|
@@ -1132,7 +1133,7 @@ class ExperimentRunAnnotation(Base):
|
|
|
1132
1133
|
|
|
1133
1134
|
class UserRole(Base):
|
|
1134
1135
|
__tablename__ = "user_roles"
|
|
1135
|
-
name: Mapped[
|
|
1136
|
+
name: Mapped[UserRoleName] = mapped_column(unique=True, index=True)
|
|
1136
1137
|
users: Mapped[list["User"]] = relationship("User", back_populates="role")
|
|
1137
1138
|
|
|
1138
1139
|
|
|
@@ -1231,6 +1232,8 @@ class OAuth2User(User):
|
|
|
1231
1232
|
*,
|
|
1232
1233
|
email: str,
|
|
1233
1234
|
username: str,
|
|
1235
|
+
oauth2_client_id: Optional[str] = None,
|
|
1236
|
+
oauth2_user_id: Optional[str] = None,
|
|
1234
1237
|
user_role_id: Optional[int] = None,
|
|
1235
1238
|
) -> None:
|
|
1236
1239
|
super().__init__(
|
|
@@ -1239,6 +1242,8 @@ class OAuth2User(User):
|
|
|
1239
1242
|
user_role_id=user_role_id,
|
|
1240
1243
|
reset_password=False,
|
|
1241
1244
|
auth_method="OAUTH2",
|
|
1245
|
+
oauth2_client_id=oauth2_client_id,
|
|
1246
|
+
oauth2_user_id=oauth2_user_id,
|
|
1242
1247
|
)
|
|
1243
1248
|
|
|
1244
1249
|
|
|
@@ -5,6 +5,7 @@ from typing import Annotated, Iterable, Literal, Optional, Union
|
|
|
5
5
|
|
|
6
6
|
import sqlalchemy as sa
|
|
7
7
|
from pydantic import AfterValidator, BaseModel, Field, RootModel
|
|
8
|
+
from sqlalchemy import func
|
|
8
9
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
9
10
|
|
|
10
11
|
from phoenix.utilities import hour_of_week
|
|
@@ -25,19 +26,25 @@ class _MaxDays(BaseModel):
|
|
|
25
26
|
class _MaxCount(BaseModel):
|
|
26
27
|
max_count: Annotated[int, Field(ge=0)]
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
def max_count_filter(
|
|
30
|
+
self,
|
|
31
|
+
project_rowids: Union[Iterable[int], sa.ScalarSelect[int]],
|
|
32
|
+
) -> sa.ColumnElement[bool]:
|
|
30
33
|
if self.max_count <= 0:
|
|
31
34
|
return sa.literal(False)
|
|
32
35
|
from phoenix.db.models import Trace
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
sa.select(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
ranked = (
|
|
38
|
+
sa.select(
|
|
39
|
+
Trace.id,
|
|
40
|
+
func.row_number()
|
|
41
|
+
.over(partition_by=Trace.project_rowid, order_by=Trace.start_time.desc())
|
|
42
|
+
.label("rn"),
|
|
43
|
+
)
|
|
44
|
+
.where(Trace.project_rowid.in_(project_rowids))
|
|
45
|
+
.cte("ranked")
|
|
40
46
|
)
|
|
47
|
+
return Trace.id.in_(sa.select(ranked.c.id).where(ranked.c.rn > self.max_count))
|
|
41
48
|
|
|
42
49
|
|
|
43
50
|
class MaxDaysRule(_MaxDays, BaseModel):
|
|
@@ -82,7 +89,7 @@ class MaxCountRule(_MaxCount, BaseModel):
|
|
|
82
89
|
stmt = (
|
|
83
90
|
sa.delete(Trace)
|
|
84
91
|
.where(Trace.project_rowid.in_(project_rowids))
|
|
85
|
-
.where(self.max_count_filter)
|
|
92
|
+
.where(self.max_count_filter(project_rowids))
|
|
86
93
|
.returning(Trace.project_rowid)
|
|
87
94
|
)
|
|
88
95
|
return set(await session.scalars(stmt))
|
|
@@ -106,7 +113,7 @@ class MaxDaysOrCountRule(_MaxDays, _MaxCount, BaseModel):
|
|
|
106
113
|
stmt = (
|
|
107
114
|
sa.delete(Trace)
|
|
108
115
|
.where(Trace.project_rowid.in_(project_rowids))
|
|
109
|
-
.where(sa.or_(self.max_days_filter, self.max_count_filter))
|
|
116
|
+
.where(sa.or_(self.max_days_filter, self.max_count_filter(project_rowids)))
|
|
110
117
|
.returning(Trace.project_rowid)
|
|
111
118
|
)
|
|
112
119
|
return set(await session.scalars(stmt))
|
|
@@ -7,7 +7,8 @@ from strawberry import UNSET
|
|
|
7
7
|
from strawberry.relay import GlobalID
|
|
8
8
|
from strawberry.types import Info
|
|
9
9
|
|
|
10
|
-
from phoenix.db import
|
|
10
|
+
from phoenix.db import models
|
|
11
|
+
from phoenix.db.models import UserRoleName
|
|
11
12
|
from phoenix.server.api.auth import IsAdmin, IsLocked, IsNotReadOnly
|
|
12
13
|
from phoenix.server.api.context import Context
|
|
13
14
|
from phoenix.server.api.exceptions import Unauthorized
|
|
@@ -65,13 +66,13 @@ class ApiKeyMutationMixin:
|
|
|
65
66
|
self, info: Info[Context, None], input: CreateApiKeyInput
|
|
66
67
|
) -> CreateSystemApiKeyMutationPayload:
|
|
67
68
|
assert (token_store := info.context.token_store) is not None
|
|
68
|
-
user_role =
|
|
69
|
+
user_role: UserRoleName = "SYSTEM"
|
|
69
70
|
async with info.context.db() as session:
|
|
70
71
|
# Get the system user - note this could be pushed into a dataloader
|
|
71
72
|
system_user = await session.scalar(
|
|
72
73
|
select(models.User)
|
|
73
74
|
.join(models.UserRole) # Join User with UserRole
|
|
74
|
-
.where(models.UserRole.name == user_role
|
|
75
|
+
.where(models.UserRole.name == user_role) # Filter where role is SYSTEM
|
|
75
76
|
.order_by(models.User.id)
|
|
76
77
|
.limit(1)
|
|
77
78
|
)
|
|
@@ -117,7 +118,7 @@ class ApiKeyMutationMixin:
|
|
|
117
118
|
issued_at=issued_at,
|
|
118
119
|
expiration_time=input.expires_at or None,
|
|
119
120
|
attributes=ApiKeyAttributes(
|
|
120
|
-
user_role=
|
|
121
|
+
user_role="ADMIN" if user.is_admin else "MEMBER",
|
|
121
122
|
name=input.name,
|
|
122
123
|
description=input.description,
|
|
123
124
|
),
|
|
@@ -25,7 +25,7 @@ from phoenix.auth import (
|
|
|
25
25
|
validate_password_format,
|
|
26
26
|
)
|
|
27
27
|
from phoenix.config import get_env_disable_basic_auth
|
|
28
|
-
from phoenix.db import
|
|
28
|
+
from phoenix.db import models
|
|
29
29
|
from phoenix.server.api.auth import IsAdmin, IsLocked, IsNotReadOnly
|
|
30
30
|
from phoenix.server.api.context import Context
|
|
31
31
|
from phoenix.server.api.exceptions import BadRequest, Conflict, NotFound, Unauthorized
|
|
@@ -256,16 +256,8 @@ class UserMutationMixin:
|
|
|
256
256
|
set(input.user_ids),
|
|
257
257
|
)
|
|
258
258
|
)
|
|
259
|
-
system_user_role_id = (
|
|
260
|
-
|
|
261
|
-
.where(models.UserRole.name == enums.UserRole.SYSTEM.value)
|
|
262
|
-
.scalar_subquery()
|
|
263
|
-
)
|
|
264
|
-
admin_user_role_id = (
|
|
265
|
-
select(models.UserRole.id)
|
|
266
|
-
.where(models.UserRole.name == enums.UserRole.ADMIN.value)
|
|
267
|
-
.scalar_subquery()
|
|
268
|
-
)
|
|
259
|
+
system_user_role_id = select(models.UserRole.id).filter_by(name="SYSTEM").scalar_subquery()
|
|
260
|
+
admin_user_role_id = select(models.UserRole.id).filter_by(name="ADMIN").scalar_subquery()
|
|
269
261
|
default_admin_user_id = (
|
|
270
262
|
select(models.User.id)
|
|
271
263
|
.where(
|
phoenix/server/api/queries.py
CHANGED
|
@@ -18,7 +18,7 @@ from phoenix.config import (
|
|
|
18
18
|
get_env_database_allocated_storage_capacity_gibibytes,
|
|
19
19
|
getenv,
|
|
20
20
|
)
|
|
21
|
-
from phoenix.db import
|
|
21
|
+
from phoenix.db import models
|
|
22
22
|
from phoenix.db.constants import DEFAULT_PROJECT_TRACE_RETENTION_POLICY_ID
|
|
23
23
|
from phoenix.db.helpers import SupportedSQLDialect, exclude_experiment_projects
|
|
24
24
|
from phoenix.db.models import DatasetExample as OrmExample
|
|
@@ -165,7 +165,7 @@ class Query:
|
|
|
165
165
|
stmt = (
|
|
166
166
|
select(models.User)
|
|
167
167
|
.join(models.UserRole)
|
|
168
|
-
.where(models.UserRole.name !=
|
|
168
|
+
.where(models.UserRole.name != "SYSTEM")
|
|
169
169
|
.order_by(models.User.email)
|
|
170
170
|
.options(joinedload(models.User.role))
|
|
171
171
|
)
|
|
@@ -181,7 +181,7 @@ class Query:
|
|
|
181
181
|
) -> list[UserRole]:
|
|
182
182
|
async with info.context.db() as session:
|
|
183
183
|
roles = await session.scalars(
|
|
184
|
-
select(models.UserRole).where(models.UserRole.name !=
|
|
184
|
+
select(models.UserRole).where(models.UserRole.name != "SYSTEM")
|
|
185
185
|
)
|
|
186
186
|
return [
|
|
187
187
|
UserRole(
|
|
@@ -197,7 +197,7 @@ class Query:
|
|
|
197
197
|
select(models.ApiKey)
|
|
198
198
|
.join(models.User)
|
|
199
199
|
.join(models.UserRole)
|
|
200
|
-
.where(models.UserRole.name !=
|
|
200
|
+
.where(models.UserRole.name != "SYSTEM")
|
|
201
201
|
)
|
|
202
202
|
async with info.context.db() as session:
|
|
203
203
|
api_keys = await session.scalars(stmt)
|
|
@@ -209,7 +209,7 @@ class Query:
|
|
|
209
209
|
select(models.ApiKey)
|
|
210
210
|
.join(models.User)
|
|
211
211
|
.join(models.UserRole)
|
|
212
|
-
.where(models.UserRole.name ==
|
|
212
|
+
.where(models.UserRole.name == "SYSTEM")
|
|
213
213
|
)
|
|
214
214
|
async with info.context.db() as session:
|
|
215
215
|
api_keys = await session.scalars(stmt)
|
|
@@ -37,7 +37,6 @@ from phoenix.config import (
|
|
|
37
37
|
get_env_disable_rate_limit,
|
|
38
38
|
)
|
|
39
39
|
from phoenix.db import models
|
|
40
|
-
from phoenix.db.enums import UserRole
|
|
41
40
|
from phoenix.server.bearer_auth import create_access_and_refresh_tokens
|
|
42
41
|
from phoenix.server.oauth2 import OAuth2Client
|
|
43
42
|
from phoenix.server.rate_limiters import (
|
|
@@ -457,9 +456,7 @@ async def _create_user(
|
|
|
457
456
|
if email_exists:
|
|
458
457
|
raise EmailAlreadyInUse(f"An account for {email} is already in use.")
|
|
459
458
|
member_role_id = (
|
|
460
|
-
select(models.UserRole.id)
|
|
461
|
-
.where(models.UserRole.name == UserRole.MEMBER.value)
|
|
462
|
-
.scalar_subquery()
|
|
459
|
+
select(models.UserRole.id).where(models.UserRole.name == "MEMBER").scalar_subquery()
|
|
463
460
|
)
|
|
464
461
|
user_id = await session.scalar(
|
|
465
462
|
insert(models.User)
|
|
@@ -15,6 +15,7 @@ from .projects import router as projects_router
|
|
|
15
15
|
from .prompts import router as prompts_router
|
|
16
16
|
from .spans import router as spans_router
|
|
17
17
|
from .traces import router as traces_router
|
|
18
|
+
from .users import router as users_router
|
|
18
19
|
from .utils import add_errors_to_responses
|
|
19
20
|
|
|
20
21
|
REST_API_VERSION = "1.0"
|
|
@@ -69,4 +70,5 @@ def create_v1_router(authentication_enabled: bool) -> APIRouter:
|
|
|
69
70
|
router.include_router(evaluations_router)
|
|
70
71
|
router.include_router(prompts_router)
|
|
71
72
|
router.include_router(projects_router)
|
|
73
|
+
router.include_router(users_router)
|
|
72
74
|
return router
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
+
from typing import Any
|
|
2
3
|
|
|
3
4
|
from pydantic import BaseModel, ConfigDict
|
|
4
5
|
|
|
6
|
+
from phoenix.db.types.db_models import UNDEFINED
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
def datetime_encoder(dt: datetime) -> str:
|
|
7
10
|
"""
|
|
@@ -43,3 +46,7 @@ class V1RoutesBaseModel(BaseModel):
|
|
|
43
46
|
[]
|
|
44
47
|
), # suppress warnings about protected namespaces starting with `model_` on pydantic 2.9
|
|
45
48
|
)
|
|
49
|
+
|
|
50
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
51
|
+
kwargs = {k: v for k, v in kwargs.items() if v is not UNDEFINED}
|
|
52
|
+
super().__init__(*args, **kwargs)
|
|
@@ -14,7 +14,6 @@ from strawberry.relay import GlobalID
|
|
|
14
14
|
|
|
15
15
|
from phoenix.config import DEFAULT_PROJECT_NAME
|
|
16
16
|
from phoenix.db import models
|
|
17
|
-
from phoenix.db.enums import UserRole
|
|
18
17
|
from phoenix.db.helpers import exclude_experiment_projects
|
|
19
18
|
from phoenix.server.api.routers.v1.models import V1RoutesBaseModel
|
|
20
19
|
from phoenix.server.api.routers.v1.utils import (
|
|
@@ -257,7 +256,7 @@ async def update_project(
|
|
|
257
256
|
.where(models.User.id == int(request.user.identity))
|
|
258
257
|
)
|
|
259
258
|
role_name = await session.scalar(stmt)
|
|
260
|
-
if role_name !=
|
|
259
|
+
if role_name != "ADMIN":
|
|
261
260
|
raise HTTPException(
|
|
262
261
|
status_code=HTTP_403_FORBIDDEN,
|
|
263
262
|
detail="Only admins can update projects",
|
|
@@ -317,7 +316,7 @@ async def delete_project(
|
|
|
317
316
|
.where(models.User.id == int(request.user.identity))
|
|
318
317
|
)
|
|
319
318
|
role_name = await session.scalar(stmt)
|
|
320
|
-
if role_name !=
|
|
319
|
+
if role_name != "ADMIN":
|
|
321
320
|
raise HTTPException(
|
|
322
321
|
status_code=HTTP_403_FORBIDDEN,
|
|
323
322
|
detail="Only admins can delete projects",
|