arize-phoenix 11.2.1__py3-none-any.whl → 11.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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arize-phoenix
3
- Version: 11.2.1
3
+ Version: 11.3.0
4
4
  Summary: AI Observability and Evaluation
5
5
  Project-URL: Documentation, https://arize.com/docs/phoenix/
6
6
  Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
@@ -165,6 +165,7 @@ Description-Content-Type: text/markdown
165
165
  <a target="_blank" href="https://github.com/Arize-ai/phoenix/tree/main/js/packages/phoenix-mcp">
166
166
  <img src="https://badge.mcpx.dev?status=on" title="MCP Enabled"/>
167
167
  </a>
168
+ <a href="https://cursor.com/install-mcp?name=phoenix&config=eyJjb21tYW5kIjoibnB4IC15IEBhcml6ZWFpL3Bob2VuaXgtbWNwQGxhdGVzdCAtLWJhc2VVcmwgaHR0cDovL2xvY2FsaG9zdDo2MDA2IC0tYXBpS2V5IHlvdXItYXBpLWtleSJ9"><img src="https://cursor.com/deeplink/mcp-install-dark.svg" alt="Add Arize Phoenix MCP server to Cursor" height=20 /></a>
168
169
  </p>
169
170
 
170
171
  Phoenix is an open-source AI observability platform designed for experimentation, evaluation, and troubleshooting. It provides:
@@ -1,12 +1,12 @@
1
1
  phoenix/__init__.py,sha256=xkpXH76HFbEDCq8IhiFp-2GnEHx39xPMdOpV5Skew1w,5481
2
2
  phoenix/auth.py,sha256=yW78f1xWNjTE30ACGUM14nOd5BzkukhlzA9B45kSUkM,11053
3
- phoenix/config.py,sha256=ql9rAKvD45l01zmlyE8lDHCkUBgRGxYmtcZvhMSwzGs,57673
3
+ phoenix/config.py,sha256=iRwfpewHsQq0iUaidGHVEGeq4V1arzEbn3fqjxmBk1s,58129
4
4
  phoenix/datetime_utils.py,sha256=fpISOdaeDBdfIa-psFp6FJyAUPWEsiT5s3-_aLV12bg,3576
5
5
  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=R3NVFNSpKk1o0N9GhBBuvfPhVFPrY5oLJJk5xhzNpGY,23
9
+ phoenix/version.py,sha256=AKQVpPKUjXA31bxC6zOaWuLMOUf9UCfopNi6s5UU5_g,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
@@ -19,7 +19,7 @@ phoenix/db/bulk_inserter.py,sha256=MbbmKip6gFtnLP1ZA3Z-mP-zy-Qnb9bPD8mRXJQOW2c,1
19
19
  phoenix/db/constants.py,sha256=-YE2rkzcROG06_rerfnX5hC7fLzOHx1Gjw4nXhX_um4,46
20
20
  phoenix/db/engines.py,sha256=tB_8iWMDz0folryVvw29sbBUxJOB2XZ-Xx0Uexj3uns,6889
21
21
  phoenix/db/enums.py,sha256=w3O5YuJEEzVTwVDZb8b2UUFhU8yK_GosF081VVrrno0,188
22
- phoenix/db/facilitator.py,sha256=NIs_P6ARHhCOYWOddURtcHIsTMufnLp2R_6Sxqxfim0,20473
22
+ phoenix/db/facilitator.py,sha256=cYzKzY18VgFP_6l-S5ZCRT5hoTNf2Vh5SkohC37wZu8,20567
23
23
  phoenix/db/helpers.py,sha256=rbbHcl-STzcEpcXCYx6jbKzko7r3ggrWHHsXjZ48HsM,5352
24
24
  phoenix/db/migrate.py,sha256=oUrXH8yEbcpL4eh09aSCuUiSrhFli0eT5D_j4ZmYChY,2797
25
25
  phoenix/db/models.py,sha256=0avhbUmDEBZ1_NgBSr9Ck9BYxXtJTraPfQqDGZFE2-Y,60388
@@ -91,14 +91,14 @@ phoenix/pointcloud/pointcloud.py,sha256=SN_1wXZcwKrtSnHGZLDZGx71orqE1WyVF7E-D58d
91
91
  phoenix/pointcloud/projectors.py,sha256=TQgwc9cJDjJkin1WZyZzgl3HsYrLLiyWD7Czy4jNW3U,1088
92
92
  phoenix/pointcloud/umap_parameters.py,sha256=db_WEPoamuWtopZx7tQfAXPnoE0MS8FkAV0_ThjEx_Q,1735
93
93
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
- phoenix/server/app.py,sha256=-K4Xs1vKwOt_lhNo5InMAp2nnVpEn76H87uQ_cCyY0Y,44905
94
+ phoenix/server/app.py,sha256=bnD2bdKb4s8TLePmwcgyoeShVKN_w-U2J4CAPQ8MfHc,45325
95
95
  phoenix/server/authorization.py,sha256=fofeRwuoodCUB3DQYPCuAgIyeiwopXW0tkH_KZvU0Rg,1848
96
96
  phoenix/server/bearer_auth.py,sha256=b2iHV2nwvWlZJ2O_nWOzHctJ0aUrEIOygIDrO7VOCSw,6700
97
97
  phoenix/server/dml_event.py,sha256=MjJmVEKytq75chBOSyvYDusUnEbg1pHpIjR3pZkUaJA,2838
98
98
  phoenix/server/dml_event_handler.py,sha256=gkDIONyTz9sLbSA6qOZCigiO5val-fvVcLzDrWNcVcg,8306
99
99
  phoenix/server/grpc_server.py,sha256=dod29zE_Zlir7NyLcdVM8GH3P8sy-9ykzfaBfVifyE4,4656
100
100
  phoenix/server/jwt_store.py,sha256=B6uVildN_dQDTG_-aHHvuVSI7wIVK1yvED-_y6se2GU,16905
101
- phoenix/server/main.py,sha256=SvLh2gB1F1Rh2LMcEx-W5gtOoGTpBjGl1tT10fG62Ns,18792
101
+ phoenix/server/main.py,sha256=UBwxrQIEE7ci-SbE6GAlRYmbMHooI6JYG6sG-UpBFFs,18905
102
102
  phoenix/server/oauth2.py,sha256=GvUqZBoZ5dG-l2G1RMl1SUcN10jNAjaMXFznMSWz2Zs,3336
103
103
  phoenix/server/prometheus.py,sha256=1KjvSfjSa2-BPjDybVMM_Kag316CsN-Zwt64YNr_snc,7825
104
104
  phoenix/server/rate_limiters.py,sha256=cFc73D2NaxqNZZDbwfIDw4So-fRVOJPBtqxOZ8Qky_s,7155
@@ -109,14 +109,15 @@ phoenix/server/types.py,sha256=b17xahdt6uwDdUYul0xctu7TbBC65AjarlhUzOiXFNE,7443
109
109
  phoenix/server/api/README.md,sha256=Pyq1PLPgTzXAswrfIhGXrjI3Skq8it2jTVnanT6Ba4Q,1162
110
110
  phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
111
111
  phoenix/server/api/auth.py,sha256=cvKH2FQLL7PasiqZMHgu9P4qchhEG7a7P9Nxy35FoIQ,1551
112
- phoenix/server/api/context.py,sha256=RzPfhs0jaHIRtwcSv5sQNDqeTjNgy1FEpN7-oC1CJYs,8882
112
+ phoenix/server/api/context.py,sha256=mqsq_8Ru50e-PxKWNTzh9zptb1PFjYFUf58uW59UYL0,8996
113
113
  phoenix/server/api/exceptions.py,sha256=TA0JuY2YRnj35qGuMSQ8d0ToHum9gWm9W--3fSKHrX0,1171
114
114
  phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
115
115
  phoenix/server/api/queries.py,sha256=jd7iz0BBX13bMIOLCkAdBOjkEsfjoV0qC27FhP_8WhQ,44874
116
116
  phoenix/server/api/schema.py,sha256=fcs36xQwFF_Qe41_5cWR8wYpDvOrnbcyTeo5WNMbDsA,1702
117
117
  phoenix/server/api/subscriptions.py,sha256=ZOGNsLVr5TNjCWgbzO7Eq6Ls_NRdJH9AxC0cW_v0vhM,25332
118
118
  phoenix/server/api/utils.py,sha256=quCBRcusc6PUq9tJq7M8PgwFZp7nXgVAxtbw8feribY,833
119
- phoenix/server/api/dataloaders/__init__.py,sha256=VHmZ_0H3WYOluc70_UE4VkXISSIXmv-PftbbgdawQM8,6710
119
+ phoenix/server/api/dataloaders/__init__.py,sha256=ddiX1BdbyGkPTzMZNo-hkF_2kqIquelBUFvQejnAJYk,6834
120
+ phoenix/server/api/dataloaders/annotation_configs_by_project.py,sha256=_Nfiug9o01JimU3Z0LpZJ0uaMCjchXomyt_dYAxPFRY,1178
120
121
  phoenix/server/api/dataloaders/annotation_summaries.py,sha256=U-mVB6pY65umyjtmF-cLGJAp5QCAaB7psgTie6_gLGI,12943
121
122
  phoenix/server/api/dataloaders/average_experiment_run_latency.py,sha256=GLFoFAbztOH-0FVzzZ77mATIO63UcjB50j3qXiNi-tE,1811
122
123
  phoenix/server/api/dataloaders/dataset_example_revisions.py,sha256=xF7M2dg3UmjhdCrscnztCIBBI0cg3RF48IIqvilpc18,4623
@@ -154,7 +155,7 @@ phoenix/server/api/dataloaders/span_cost_details_by_span_cost.py,sha256=f8ztQACG
154
155
  phoenix/server/api/dataloaders/span_cost_summary_by_experiment.py,sha256=O3KVRgoAfuP32w2wmQdnXAa8GWnxm9wFJPqng9Ct2LQ,2577
155
156
  phoenix/server/api/dataloaders/span_cost_summary_by_experiment_run.py,sha256=IJFirEPeR1UGKTg6Gz3MJQGDigoPy6SaFnUdBibyVac,2539
156
157
  phoenix/server/api/dataloaders/span_cost_summary_by_generative_model.py,sha256=Fhp0NPsoSbTBgnE38hregVVeVHEhPw_QANiOfNyaTf8,2295
157
- phoenix/server/api/dataloaders/span_cost_summary_by_project.py,sha256=Rn74_gc1O6JqXYYgo4BNKWcEkjB9QPAtcHgqbBHyP1k,5294
158
+ phoenix/server/api/dataloaders/span_cost_summary_by_project.py,sha256=UjLkGvsVAY5-vltd08iR_NyWZ-_dWLc70yglMKSPPzY,5203
158
159
  phoenix/server/api/dataloaders/span_cost_summary_by_project_session.py,sha256=kvsMK8GkFBubMiKZ0KwDk5O2D3LvXIg_zKT66MoKazE,2362
159
160
  phoenix/server/api/dataloaders/span_cost_summary_by_trace.py,sha256=XCq1mRGwNN5xucf4ea-V1cHus_VQQJyjR40UKCOmWHg,2274
160
161
  phoenix/server/api/dataloaders/span_costs.py,sha256=hlNrofQNNuGi4XFxOt7OV_ceBJ6mu_aKsDMz7SSoM3A,1161
@@ -317,7 +318,7 @@ phoenix/server/api/types/ModelInterface.py,sha256=Qe7H23wDb_Q2-HmeY2t0R5Jsn4aAfY
317
318
  phoenix/server/api/types/NumericRange.py,sha256=afEjgF97Go_OvmjMggbPBt-zGM8IONewAyEiKEHRds0,192
318
319
  phoenix/server/api/types/PerformanceMetric.py,sha256=KFkmJDqP43eDUtARQOUqR7NYcxvL6Vh2uisHWU6H3ko,387
319
320
  phoenix/server/api/types/PlaygroundModel.py,sha256=IqJFxsAAJMRyaFI9ryI3GQrpFOJ5Llf6kIutEO-tFvM,321
320
- phoenix/server/api/types/Project.py,sha256=VTz9QXFfnkz0XOm1bGz3FffhCodg_YmjKafiwZ_Qh1I,31580
321
+ phoenix/server/api/types/Project.py,sha256=-Be5ZL0mBfCV2pTi6oKYt8napwQWiCnUjSGdoSfnSJU,31154
321
322
  phoenix/server/api/types/ProjectSession.py,sha256=uwqTsDTfSGz13AvP-cwS_mJR5JZ1lHqu10ungbl7g5s,6245
322
323
  phoenix/server/api/types/ProjectTraceRetentionPolicy.py,sha256=tYy2kgalPDyuaYZr0VUHjH0YpXaiF_QOzg5yfaV_c7c,3782
323
324
  phoenix/server/api/types/Prompt.py,sha256=ccP4eq1e38xbF0afclGWLOuDpBVpNbJ3AOSRClF8yFQ,4955
@@ -345,7 +346,7 @@ phoenix/server/api/types/ToolDefinition.py,sha256=T6UH2vcbuPBDy7jKYOqMth2NdqxMPg
345
346
  phoenix/server/api/types/Trace.py,sha256=iaSAicxMHTrnUTYxNfMwFMglVeptqu7nF_AHS6k-QGw,9718
346
347
  phoenix/server/api/types/TraceAnnotation.py,sha256=qUO9DhTIAOKIYqNd5uHqLAsVTsJLSddkXo-gmyjnPBI,1964
347
348
  phoenix/server/api/types/UMAPPoints.py,sha256=49sWnxjcAJKRzqUY71Fa0tOPti5XjIIFT5cSg6oNu_U,1650
348
- phoenix/server/api/types/User.py,sha256=iTVUrI8U6-asOhBt1bOZNtoRAaRNC4WHgR1Uv2rHnWQ,1975
349
+ phoenix/server/api/types/User.py,sha256=20q4K_dwWHKdCTLFOmpdbt_OjdGv-98z2dHhwh7RmnI,2412
349
350
  phoenix/server/api/types/UserApiKey.py,sha256=EcsPNxV_PtgpqwA_bPTj_aRYt15l6X24YDy20hUPywU,1251
350
351
  phoenix/server/api/types/UserRole.py,sha256=yjyVsA9mKo0tYEjK9pjtfDL2MZKvGyh_-Eednc88J64,342
351
352
  phoenix/server/api/types/ValidationResult.py,sha256=pHwdYk4J7SJ5xhlWWHg_6qWkfk4rjOx-bSkGHvkDE3Q,142
@@ -382,10 +383,10 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
382
383
  phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
383
384
  phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
384
385
  phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
385
- phoenix/server/static/.vite/manifest.json,sha256=IKfD11oTZKV9QuRQGK7NsGMdP3rBQ01s-MdYzCLaROw,2165
386
- phoenix/server/static/assets/components-PP4ssj43.js,sha256=Mjkx3KMo6lJpN-mHqrmPHU64VwNLbIyaD8WxSf7tQPo,612894
387
- phoenix/server/static/assets/index-COyfeNsl.js,sha256=ale5Ej4kjKzk1saz5gtbfRIdrzT1SKrSOCiwxRRXzSA,61540
388
- phoenix/server/static/assets/pages-DozDSxRj.js,sha256=1uXw_Rs8VZGdV1WgKcuBJO0lnieXYAjDXlUHWFY6Ifs,1140989
386
+ phoenix/server/static/.vite/manifest.json,sha256=bXQJJbyae7gYzkJjXGq6p_LFCaTkDdqZoSloiWGQXTc,2165
387
+ phoenix/server/static/assets/components-DlL7ybQ2.js,sha256=Wy6GpaWRnmvUz9DLZl-iBqTHALBYdFo4jfveQlCjZvI,613791
388
+ phoenix/server/static/assets/index-QP9R8k34.js,sha256=X553nmol5rlDC4AgwTxyIpEwnEvdPYIeOIt46Mw8Ky8,61540
389
+ phoenix/server/static/assets/pages-B7wCtpad.js,sha256=_TbR0i5E22DvJprdBbilq40brxQ0dr41hSgT8uPpjhw,1141211
389
390
  phoenix/server/static/assets/vendor-DqQvHbPa.js,sha256=iojYxZrTZAvg1A6a3dRVtSDg9SJ03oG_c0F9U3Qsjvg,2738792
390
391
  phoenix/server/static/assets/vendor-WIZid84E.css,sha256=spZD2r7XL5GfLO13ln-IuXfnjAref8l6g_n_AvxxOlI,5517
391
392
  phoenix/server/static/assets/vendor-arizeai-CLX44PFA.js,sha256=CbM509A_yUJj9uB02t8s2SzFa2boT74Usuzt9FpOZM8,181769
@@ -394,7 +395,7 @@ phoenix/server/static/assets/vendor-recharts-B2PJDrnX.js,sha256=kepv82lpyuWOFs_R
394
395
  phoenix/server/static/assets/vendor-shiki-CNbrFjf9.js,sha256=RNePvHL4S7oRtI_kOMiiQGabP3TD2thldyEdHdBoEnA,8980312
395
396
  phoenix/server/static/assets/vendor-three-C5WAXd5r.js,sha256=ELkg06u70N7h8oFmvqdoHyPuUf9VgGEWeT4LKFx4VWo,620975
396
397
  phoenix/server/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
397
- phoenix/server/templates/index.html,sha256=TxaZTZKUz7-xQ3XlPO3DAPMj6S1rMEr5v6g1UmgaW70,6761
398
+ phoenix/server/templates/index.html,sha256=rTdJZOlbZmm1dMCrHWikAwcecZDxduPU5zCFd2h2cbs,6819
398
399
  phoenix/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
399
400
  phoenix/session/client.py,sha256=uw5WlCuFcN_eEj7Ko2bhJVcaihEIp7Evy50KnL6Sq-k,35602
400
401
  phoenix/session/data_extractor.py,sha256=Y0RzYFaNy9fQj8PEIeQ76TBZ90_E1FW7bXu3K5x0EZY,2782
@@ -432,9 +433,9 @@ phoenix/utilities/project.py,sha256=auVpARXkDb-JgeX5f2aStyFIkeKvGwN9l7qrFeJMVxI,
432
433
  phoenix/utilities/re.py,sha256=6YyUWIkv0zc2SigsxfOWIHzdpjKA_TZo2iqKq7zJKvw,2081
433
434
  phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
434
435
  phoenix/utilities/template_formatters.py,sha256=gh9PJD6WEGw7TEYXfSst1UR4pWWwmjxMLrDVQ_CkpkQ,2779
435
- arize_phoenix-11.2.1.dist-info/METADATA,sha256=bBcHweIVeSUkIoS6EnVELFPIXhPfPy7VhLSJAFbVm-c,27369
436
- arize_phoenix-11.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
437
- arize_phoenix-11.2.1.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
438
- arize_phoenix-11.2.1.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
439
- arize_phoenix-11.2.1.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
440
- arize_phoenix-11.2.1.dist-info/RECORD,,
436
+ arize_phoenix-11.3.0.dist-info/METADATA,sha256=NAkmRQDujGqHLFm2mpiXXanrLRnDBHn1CCPWJgqU0ow,27693
437
+ arize_phoenix-11.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
438
+ arize_phoenix-11.3.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
439
+ arize_phoenix-11.3.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
440
+ arize_phoenix-11.3.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
441
+ arize_phoenix-11.3.0.dist-info/RECORD,,
phoenix/config.py CHANGED
@@ -223,6 +223,12 @@ Examples:
223
223
  - With a sub-path: "https://example.com/phoenix"
224
224
  - Without a sub-path: "https://phoenix.example.com"
225
225
  """
226
+ ENV_PHOENIX_MANAGEMENT_URL = "PHOENIX_MANAGEMENT_URL"
227
+ """
228
+ The URL to use for redirecting to a management interface that may be hosting Phoenix. If set, and
229
+ the current user is within PHOENIX_ADMINS, a link will be added to the navigation menu to return to
230
+ this URL.
231
+ """
226
232
 
227
233
 
228
234
  # SMTP settings
@@ -818,7 +824,7 @@ def get_env_csrf_trusted_origins() -> list[str]:
818
824
 
819
825
  def get_env_admins() -> dict[str, str]:
820
826
  """
821
- Parse the PHOENIX_ADMINS environment variable to extract the comma separated pairs of
827
+ Parse the PHOENIX_ADMINS environment variable to extract the semicolon separated pairs of
822
828
  username and email. The last equal sign (=) in each pair is used to separate the username from
823
829
  the email.
824
830
 
@@ -1540,6 +1546,13 @@ def get_env_fullstory_org() -> Optional[str]:
1540
1546
  return getenv(ENV_PHOENIX_FULLSTORY_ORG)
1541
1547
 
1542
1548
 
1549
+ def get_env_management_url() -> Optional[str]:
1550
+ """
1551
+ Gets the value of the PHOENIX_MANAGEMENT_URL environment variable.
1552
+ """
1553
+ return getenv(ENV_PHOENIX_MANAGEMENT_URL)
1554
+
1555
+
1543
1556
  def verify_server_environment_variables() -> None:
1544
1557
  """Verify that the environment variables are set correctly. Raises an error otherwise."""
1545
1558
  get_env_root_url()
phoenix/db/facilitator.py CHANGED
@@ -519,4 +519,5 @@ async def _ensure_model_costs(db: DbSessionFactory) -> None:
519
519
  sa.update(models.GenerativeModel)
520
520
  .values(deleted_at=sa.func.now())
521
521
  .where(models.GenerativeModel.id.in_([m.id for m in remaining_models]))
522
+ .where(~sa.exists().where(models.GenerativeModel.id == models.SpanCost.model_id))
522
523
  )
@@ -15,6 +15,7 @@ from phoenix.auth import (
15
15
  from phoenix.core.model_schema import Model
16
16
  from phoenix.db import models
17
17
  from phoenix.server.api.dataloaders import (
18
+ AnnotationConfigsByProjectDataLoader,
18
19
  AnnotationSummaryDataLoader,
19
20
  AverageExperimentRunLatencyDataLoader,
20
21
  CacheForDataLoaders,
@@ -82,6 +83,7 @@ from phoenix.server.types import (
82
83
 
83
84
  @dataclass
84
85
  class DataLoaders:
86
+ annotation_configs_by_project: AnnotationConfigsByProjectDataLoader
85
87
  annotation_summaries: AnnotationSummaryDataLoader
86
88
  average_experiment_run_latency: AverageExperimentRunLatencyDataLoader
87
89
  dataset_example_revisions: DatasetExampleRevisionsDataLoader
@@ -4,6 +4,7 @@ from phoenix.server.api.dataloaders.span_cost_detail_summary_entries_by_project_
4
4
  SpanCostDetailSummaryEntriesByProjectSessionDataLoader,
5
5
  )
6
6
 
7
+ from .annotation_configs_by_project import AnnotationConfigsByProjectDataLoader
7
8
  from .annotation_summaries import AnnotationSummaryCache, AnnotationSummaryDataLoader
8
9
  from .average_experiment_run_latency import AverageExperimentRunLatencyDataLoader
9
10
  from .dataset_example_revisions import DatasetExampleRevisionsDataLoader
@@ -61,6 +62,7 @@ from .user_roles import UserRolesDataLoader
61
62
  from .users import UsersDataLoader
62
63
 
63
64
  __all__ = [
65
+ "AnnotationConfigsByProjectDataLoader",
64
66
  "AnnotationSummaryDataLoader",
65
67
  "AverageExperimentRunLatencyDataLoader",
66
68
  "CacheForDataLoaders",
@@ -0,0 +1,31 @@
1
+ from collections import defaultdict
2
+
3
+ from sqlalchemy import select
4
+ from strawberry.dataloader import DataLoader
5
+ from typing_extensions import TypeAlias
6
+
7
+ from phoenix.db import models
8
+ from phoenix.server.types import DbSessionFactory
9
+
10
+ ProjectId: TypeAlias = int
11
+ Key: TypeAlias = ProjectId
12
+ Result: TypeAlias = tuple[models.AnnotationConfig, ...]
13
+
14
+
15
+ class AnnotationConfigsByProjectDataLoader(DataLoader[Key, Result]):
16
+ def __init__(self, db: DbSessionFactory) -> None:
17
+ super().__init__(load_fn=self._load_fn)
18
+ self._db = db
19
+
20
+ async def _load_fn(self, keys: list[Key]) -> list[Result]:
21
+ stmt = (
22
+ select(models.ProjectAnnotationConfig.project_id, models.AnnotationConfig)
23
+ .join_from(models.ProjectAnnotationConfig, models.AnnotationConfig)
24
+ .where(models.ProjectAnnotationConfig.project_id.in_(keys))
25
+ )
26
+ results: defaultdict[Key, list[models.AnnotationConfig]] = defaultdict(list)
27
+ async with self._db() as session:
28
+ data = await session.stream(stmt)
29
+ async for id_, config in data:
30
+ results[id_].append(config)
31
+ return [tuple(results[k]) for k in keys]
@@ -119,20 +119,18 @@ def _get_stmt(
119
119
  coalesce(func.sum(models.SpanCost.completion_tokens), 0).label("completion_tokens"),
120
120
  coalesce(func.sum(models.SpanCost.total_tokens), 0).label("total_tokens"),
121
121
  )
122
- .select_from(models.Trace)
123
- .join(models.Span, models.Span.trace_rowid == models.Trace.id)
124
- .join(models.SpanCost, models.Span.id == models.SpanCost.span_rowid)
122
+ .join_from(models.SpanCost, models.Trace)
125
123
  .group_by(pid)
126
124
  )
127
125
 
128
126
  if start_time:
129
- stmt = stmt.where(start_time <= models.Span.start_time)
127
+ stmt = stmt.where(start_time <= models.Trace.start_time)
130
128
  if end_time:
131
- stmt = stmt.where(models.Span.start_time < end_time)
129
+ stmt = stmt.where(models.Trace.start_time < end_time)
132
130
 
133
131
  if filter_condition:
134
132
  sf = SpanFilter(filter_condition)
135
- stmt = sf(stmt)
133
+ stmt = sf(stmt.join_from(models.SpanCost, models.Span))
136
134
 
137
135
  project_ids = [rowid for rowid in params]
138
136
  stmt = stmt.where(pid.in_(project_ids))
@@ -655,18 +655,9 @@ class Project(Node):
655
655
  last=last,
656
656
  before=before if isinstance(before, CursorString) else None,
657
657
  )
658
- async with info.context.db() as session:
659
- annotation_configs = await session.stream_scalars(
660
- select(models.AnnotationConfig)
661
- .join(
662
- models.ProjectAnnotationConfig,
663
- models.AnnotationConfig.id
664
- == models.ProjectAnnotationConfig.annotation_config_id,
665
- )
666
- .where(models.ProjectAnnotationConfig.project_id == self.project_rowid)
667
- .order_by(models.AnnotationConfig.name)
668
- )
669
- data = [to_gql_annotation_config(config) async for config in annotation_configs]
658
+ loader = info.context.data_loaders.annotation_configs_by_project
659
+ configs = await loader.load(self.project_rowid)
660
+ data = [to_gql_annotation_config(config) for config in configs]
670
661
  return connection_from_list(data=data, args=args)
671
662
 
672
663
  @strawberry.field
@@ -7,6 +7,7 @@ from strawberry import Private
7
7
  from strawberry.relay import Node, NodeID
8
8
  from strawberry.types import Info
9
9
 
10
+ from phoenix.config import get_env_admins
10
11
  from phoenix.db import models
11
12
  from phoenix.server.api.context import Context
12
13
  from phoenix.server.api.exceptions import NotFound
@@ -42,6 +43,15 @@ class User(Node):
42
43
  )
43
44
  return [to_gql_api_key(api_key) for api_key in api_keys]
44
45
 
46
+ @strawberry.field
47
+ async def is_management_user(self) -> bool:
48
+ initial_admins = get_env_admins()
49
+ # this field is only visible to initial admins as they are the ones likely to have access to
50
+ # a management interface / the phoenix environment.
51
+ if self.email in initial_admins or self.email == "admin@localhost":
52
+ return True
53
+ return False
54
+
45
55
 
46
56
  def to_gql_user(user: models.User, api_keys: Optional[list[models.ApiKey]] = None) -> User:
47
57
  """
phoenix/server/app.py CHANGED
@@ -72,6 +72,7 @@ from phoenix.exceptions import PhoenixMigrationError
72
72
  from phoenix.pointcloud.umap_parameters import UMAPParameters
73
73
  from phoenix.server.api.context import Context, DataLoaders
74
74
  from phoenix.server.api.dataloaders import (
75
+ AnnotationConfigsByProjectDataLoader,
75
76
  AnnotationSummaryDataLoader,
76
77
  AverageExperimentRunLatencyDataLoader,
77
78
  CacheForDataLoaders,
@@ -231,6 +232,8 @@ class AppConfig(NamedTuple):
231
232
  auto_login_idp_name: Optional[str] = None
232
233
  fullstory_org: Optional[str] = None
233
234
  """ FullStory organization ID for web analytics tracking """
235
+ management_url: Optional[str] = None
236
+ """ URL for a phoenix management interface, only visible to management users """
234
237
 
235
238
 
236
239
  class Static(StaticFiles):
@@ -297,6 +300,7 @@ class Static(StaticFiles):
297
300
  "basic_auth_disabled": self._app_config.basic_auth_disabled,
298
301
  "auto_login_idp_name": self._app_config.auto_login_idp_name,
299
302
  "fullstory_org": self._app_config.fullstory_org,
303
+ "management_url": self._app_config.management_url,
300
304
  },
301
305
  )
302
306
  except Exception as e:
@@ -642,6 +646,7 @@ def create_graphql_router(
642
646
  last_updated_at=last_updated_at,
643
647
  event_queue=event_queue,
644
648
  data_loaders=DataLoaders(
649
+ annotation_configs_by_project=AnnotationConfigsByProjectDataLoader(db),
645
650
  average_experiment_run_latency=AverageExperimentRunLatencyDataLoader(db),
646
651
  dataset_example_revisions=DatasetExampleRevisionsDataLoader(db),
647
652
  dataset_example_spans=DatasetExampleSpansDataLoader(db),
@@ -847,6 +852,7 @@ def create_app(
847
852
  basic_auth_disabled: bool = False,
848
853
  bulk_inserter_factory: Optional[Callable[..., BulkInserter]] = None,
849
854
  allowed_origins: Optional[list[str]] = None,
855
+ management_url: Optional[str] = None,
850
856
  ) -> FastAPI:
851
857
  verify_server_environment_variables()
852
858
  if model.embedding_dimensions:
@@ -1026,6 +1032,7 @@ def create_app(
1026
1032
  basic_auth_disabled=basic_auth_disabled,
1027
1033
  auto_login_idp_name=auto_login_idp_name,
1028
1034
  fullstory_org=Settings.fullstory_org,
1035
+ management_url=management_url,
1029
1036
  ),
1030
1037
  ),
1031
1038
  name="static",
phoenix/server/main.py CHANGED
@@ -32,6 +32,7 @@ from phoenix.config import (
32
32
  get_env_log_migrations,
33
33
  get_env_logging_level,
34
34
  get_env_logging_mode,
35
+ get_env_management_url,
35
36
  get_env_oauth2_settings,
36
37
  get_env_password_reset_token_expiry,
37
38
  get_env_port,
@@ -377,6 +378,7 @@ def main() -> None:
377
378
  )
378
379
 
379
380
  allowed_origins = get_env_allowed_origins()
381
+ management_url = get_env_management_url()
380
382
 
381
383
  # Get TLS configuration
382
384
  tls_enabled_for_http = get_env_tls_enabled_for_http()
@@ -455,6 +457,7 @@ def main() -> None:
455
457
  email_sender=email_sender,
456
458
  oauth2_client_configs=get_env_oauth2_settings(),
457
459
  allowed_origins=allowed_origins,
460
+ management_url=management_url,
458
461
  )
459
462
 
460
463
  # Configure server with TLS if enabled
@@ -1,22 +1,22 @@
1
1
  {
2
- "_components-PP4ssj43.js": {
3
- "file": "assets/components-PP4ssj43.js",
2
+ "_components-DlL7ybQ2.js": {
3
+ "file": "assets/components-DlL7ybQ2.js",
4
4
  "name": "components",
5
5
  "imports": [
6
6
  "_vendor-DqQvHbPa.js",
7
- "_pages-DozDSxRj.js",
7
+ "_pages-B7wCtpad.js",
8
8
  "_vendor-arizeai-CLX44PFA.js",
9
9
  "_vendor-codemirror-Du3XyJnB.js",
10
10
  "_vendor-three-C5WAXd5r.js"
11
11
  ]
12
12
  },
13
- "_pages-DozDSxRj.js": {
14
- "file": "assets/pages-DozDSxRj.js",
13
+ "_pages-B7wCtpad.js": {
14
+ "file": "assets/pages-B7wCtpad.js",
15
15
  "name": "pages",
16
16
  "imports": [
17
17
  "_vendor-DqQvHbPa.js",
18
18
  "_vendor-arizeai-CLX44PFA.js",
19
- "_components-PP4ssj43.js",
19
+ "_components-DlL7ybQ2.js",
20
20
  "_vendor-codemirror-Du3XyJnB.js",
21
21
  "_vendor-recharts-B2PJDrnX.js"
22
22
  ]
@@ -69,15 +69,15 @@
69
69
  "name": "vendor-three"
70
70
  },
71
71
  "index.tsx": {
72
- "file": "assets/index-COyfeNsl.js",
72
+ "file": "assets/index-QP9R8k34.js",
73
73
  "name": "index",
74
74
  "src": "index.tsx",
75
75
  "isEntry": true,
76
76
  "imports": [
77
77
  "_vendor-DqQvHbPa.js",
78
78
  "_vendor-arizeai-CLX44PFA.js",
79
- "_pages-DozDSxRj.js",
80
- "_components-PP4ssj43.js",
79
+ "_pages-B7wCtpad.js",
80
+ "_components-DlL7ybQ2.js",
81
81
  "_vendor-three-C5WAXd5r.js",
82
82
  "_vendor-codemirror-Du3XyJnB.js",
83
83
  "_vendor-shiki-CNbrFjf9.js",