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

Files changed (27) hide show
  1. {arize_phoenix-11.30.0.dist-info → arize_phoenix-11.32.0.dist-info}/METADATA +17 -17
  2. {arize_phoenix-11.30.0.dist-info → arize_phoenix-11.32.0.dist-info}/RECORD +26 -25
  3. phoenix/db/types/trace_retention.py +1 -1
  4. phoenix/experiments/functions.py +69 -19
  5. phoenix/server/api/dataloaders/document_evaluations.py +6 -9
  6. phoenix/server/api/routers/v1/annotations.py +128 -5
  7. phoenix/server/api/routers/v1/documents.py +47 -79
  8. phoenix/server/api/routers/v1/experiment_runs.py +71 -31
  9. phoenix/server/api/routers/v1/spans.py +2 -48
  10. phoenix/server/api/routers/v1/traces.py +19 -55
  11. phoenix/server/api/types/Dataset.py +8 -66
  12. phoenix/server/api/types/DatasetExperimentAnnotationSummary.py +10 -0
  13. phoenix/server/api/types/DocumentAnnotation.py +92 -0
  14. phoenix/server/api/types/Span.py +8 -2
  15. phoenix/server/api/types/TraceAnnotation.py +8 -5
  16. phoenix/server/cost_tracking/model_cost_manifest.json +91 -0
  17. phoenix/server/static/.vite/manifest.json +9 -9
  18. phoenix/server/static/assets/{components-BBwXqJXQ.js → components-Cs9c4Nxp.js} +1 -1
  19. phoenix/server/static/assets/{index-C_gU3x10.js → index-D1FDMBMV.js} +1 -1
  20. phoenix/server/static/assets/{pages-YmQb55Uo.js → pages-Cbj9SjBx.js} +488 -463
  21. phoenix/trace/projects.py +6 -0
  22. phoenix/version.py +1 -1
  23. phoenix/server/api/types/Evaluation.py +0 -40
  24. {arize_phoenix-11.30.0.dist-info → arize_phoenix-11.32.0.dist-info}/WHEEL +0 -0
  25. {arize_phoenix-11.30.0.dist-info → arize_phoenix-11.32.0.dist-info}/entry_points.txt +0 -0
  26. {arize_phoenix-11.30.0.dist-info → arize_phoenix-11.32.0.dist-info}/licenses/IP_NOTICE +0 -0
  27. {arize_phoenix-11.30.0.dist-info → arize_phoenix-11.32.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arize-phoenix
3
- Version: 11.30.0
3
+ Version: 11.32.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
@@ -201,14 +201,14 @@ The `arize-phoenix` package includes the entire Phoenix platfom. However if you
201
201
 
202
202
  ### Subpackages
203
203
 
204
- | Package | Language | Description |
205
- | --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
206
- | [arize-phoenix-otel](https://github.com/Arize-ai/phoenix/tree/main/packages/phoenix-otel) | Python [![PyPI Version](https://img.shields.io/pypi/v/arize-phoenix-otel)](https://pypi.org/project/arize-phoenix-otel/) | Provides a lightweight wrapper around OpenTelemetry primitives with Phoenix-aware defaults |
207
- | [arize-phoenix-client](https://github.com/Arize-ai/phoenix/tree/main/packages/phoenix-client) | Python [![PyPI Version](https://img.shields.io/pypi/v/arize-phoenix-client)](https://pypi.org/project/arize-phoenix-client/) | Lightweight client for interacting with the Phoenix server via its OpenAPI REST interface |
208
- | [arize-phoenix-evals](https://github.com/Arize-ai/phoenix/tree/main/packages/phoenix-evals) | Python [![PyPI Version](https://img.shields.io/pypi/v/arize-phoenix-evals)](https://pypi.org/project/arize-phoenix-evals/) | Tooling to evaluate LLM applications including RAG relevance, answer relevance, and more |
209
- | [@arizeai/phoenix-client](https://github.com/Arize-ai/phoenix/tree/main/js/packages/phoenix-client) | JavaScript [![NPM Version](https://img.shields.io/npm/v/%40arizeai%2Fphoenix-client)](https://www.npmjs.com/package/@arizeai/phoenix-client) | Client for the Arize Phoenix API |
210
- | [@arizeai/phoenix-evals](https://github.com/Arize-ai/phoenix/tree/main/js/packages/phoenix-evals) | TypeScript [![NPM Version](https://img.shields.io/npm/v/%40arizeai%2Fphoenix-evals)](https://www.npmjs.com/package/@arizeai/phoenix-evals) | TypeScript evaluation library for LLM applications (alpha release) |
211
- | [@arizeai/phoenix-mcp](https://github.com/Arize-ai/phoenix/tree/main/js/packages/phoenix-mcp) | JavaScript [![NPM Version](https://img.shields.io/npm/v/%40arizeai%2Fphoenix-mcp)](https://www.npmjs.com/package/@arizeai/phoenix-mcp) | MCP server implementation for Arize Phoenix providing unified interface to Phoenix's capabilities |
204
+ | Package | Version & Docs | Description |
205
+ | --------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
206
+ | [arize-phoenix-otel](https://github.com/Arize-ai/phoenix/tree/main/packages/phoenix-otel) | [![PyPI Version](https://img.shields.io/pypi/v/arize-phoenix-otel)](https://pypi.org/project/arize-phoenix-otel/) [![Docs](https://img.shields.io/badge/docs-blue?logo=readthedocs&logoColor=white)](https://arize-phoenix.readthedocs.io/projects/otel/en/latest/index.html) | Provides a lightweight wrapper around OpenTelemetry primitives with Phoenix-aware defaults |
207
+ | [arize-phoenix-client](https://github.com/Arize-ai/phoenix/tree/main/packages/phoenix-client) | [![PyPI Version](https://img.shields.io/pypi/v/arize-phoenix-client)](https://pypi.org/project/arize-phoenix-client/) [![Docs](https://img.shields.io/badge/docs-blue?logo=readthedocs&logoColor=white)](https://arize-phoenix.readthedocs.io/projects/client/en/latest/index.html) | Lightweight client for interacting with the Phoenix server via its OpenAPI REST interface |
208
+ | [arize-phoenix-evals](https://github.com/Arize-ai/phoenix/tree/main/packages/phoenix-evals) | [![PyPI Version](https://img.shields.io/pypi/v/arize-phoenix-evals)](https://pypi.org/project/arize-phoenix-evals/) [![Docs](https://img.shields.io/badge/docs-blue?logo=readthedocs&logoColor=white)](https://arize-phoenix.readthedocs.io/projects/evals/en/latest/index.html) | Tooling to evaluate LLM applications including RAG relevance, answer relevance, and more |
209
+ | [@arizeai/phoenix-client](https://github.com/Arize-ai/phoenix/tree/main/js/packages/phoenix-client) | [![NPM Version](https://img.shields.io/npm/v/%40arizeai%2Fphoenix-client)](https://www.npmjs.com/package/@arizeai/phoenix-client) [![Docs](https://img.shields.io/badge/docs-blue?logo=typescript&logoColor=white)](https://arize-ai.github.io/phoenix/) | Client for the Arize Phoenix API |
210
+ | [@arizeai/phoenix-evals](https://github.com/Arize-ai/phoenix/tree/main/js/packages/phoenix-evals) | [![NPM Version](https://img.shields.io/npm/v/%40arizeai%2Fphoenix-evals)](https://www.npmjs.com/package/@arizeai/phoenix-evals) [![Docs](https://img.shields.io/badge/docs-blue?logo=typescript&logoColor=white)](https://arize-ai.github.io/phoenix/) | TypeScript evaluation library for LLM applications (alpha release) |
211
+ | [@arizeai/phoenix-mcp](https://github.com/Arize-ai/phoenix/tree/main/js/packages/phoenix-mcp) | [![NPM Version](https://img.shields.io/npm/v/%40arizeai%2Fphoenix-mcp)](https://www.npmjs.com/package/@arizeai/phoenix-mcp) [![Docs](https://img.shields.io/badge/docs-blue?logo=markdown&logoColor=white)](./js/packages/phoenix-mcp/README.md) | MCP server implementation for Arize Phoenix providing unified interface to Phoenix's capabilities |
212
212
 
213
213
  ## Tracing Integrations
214
214
 
@@ -256,17 +256,17 @@ Phoenix is built on top of OpenTelemetry and is vendor, language, and framework
256
256
  | Integration | Package | Version Badge |
257
257
  | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
258
258
  | [LangChain4j](https://github.com/Arize-ai/openinference/tree/main/java/instrumentation/openinference-instrumentation-langchain4j) | `openinference-instrumentation-langchain4j` | [![Maven Central](https://img.shields.io/maven-central/v/com.arize/openinference-instrumentation-langchain4j.svg)](https://central.sonatype.com/artifact/com.arize/openinference-instrumentation-langchain4j) |
259
- | [SpringAI](https://central.sonatype.com/artifact/com.arize/openinference-instrumentation-springAI) | `openinference-instrumentation-springAI` | [![Maven Central](https://img.shields.io/maven-central/v/com.arize/openinference-instrumentation-springAI.svg)](https://central.sonatype.com/artifact/com.arize/openinference-instrumentation-springAI) |
259
+ | [SpringAI](https://central.sonatype.com/artifact/com.arize/openinference-instrumentation-springAI) | `openinference-instrumentation-springAI` | [![Maven Central](https://img.shields.io/maven-central/v/com.arize/openinference-instrumentation-springAI.svg)](https://central.sonatype.com/artifact/com.arize/openinference-instrumentation-springAI) |
260
260
 
261
261
  ### Platforms
262
262
 
263
- | Platform | Description | Docs |
264
- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
265
- | [BeeAI](https://docs.beeai.dev/observability/agents-traceability) | AI agent framework with built-in observability | [Integration Guide](https://docs.beeai.dev/observability/agents-traceability) |
266
- | [Dify](https://docs.dify.ai/en/guides/monitoring/integrate-external-ops-tools/integrate-phoenix) | Open-source LLM app development platform | [Integration Guide](https://docs.dify.ai/en/guides/monitoring/integrate-external-ops-tools/integrate-phoenix) |
267
- | [Envoy AI Gateway](https://github.com/envoyproxy/ai-gateway) | AI Gateway built on Envoy Proxy for AI workloads | [Integration Guide](https://github.com/envoyproxy/ai-gateway/tree/main/cmd/aigw#opentelemetry-setup-with-phoenix) |
268
- | [LangFlow](https://arize.com/docs/phoenix/tracing/integrations-tracing/langflow) | Visual framework for building multi-agent and RAG applications | [Integration Guide](https://arize.com/docs/phoenix/tracing/integrations-tracing/langflow) |
269
- | [LiteLLM Proxy](https://docs.litellm.ai/docs/observability/phoenix_integration#using-with-litellm-proxy) | Proxy server for LLMs | [Integration Guide](https://docs.litellm.ai/docs/observability/phoenix_integration#using-with-litellm-proxy) |
263
+ | Platform | Description | Docs |
264
+ | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
265
+ | [BeeAI](https://docs.beeai.dev/observability/agents-traceability) | AI agent framework with built-in observability | [Integration Guide](https://docs.beeai.dev/observability/agents-traceability) |
266
+ | [Dify](https://docs.dify.ai/en/guides/monitoring/integrate-external-ops-tools/integrate-phoenix) | Open-source LLM app development platform | [Integration Guide](https://docs.dify.ai/en/guides/monitoring/integrate-external-ops-tools/integrate-phoenix) |
267
+ | [Envoy AI Gateway](https://github.com/envoyproxy/ai-gateway) | AI Gateway built on Envoy Proxy for AI workloads | [Integration Guide](https://github.com/envoyproxy/ai-gateway/tree/main/cmd/aigw#opentelemetry-setup-with-phoenix) |
268
+ | [LangFlow](https://arize.com/docs/phoenix/tracing/integrations-tracing/langflow) | Visual framework for building multi-agent and RAG applications | [Integration Guide](https://arize.com/docs/phoenix/tracing/integrations-tracing/langflow) |
269
+ | [LiteLLM Proxy](https://docs.litellm.ai/docs/observability/phoenix_integration#using-with-litellm-proxy) | Proxy server for LLMs | [Integration Guide](https://docs.litellm.ai/docs/observability/phoenix_integration#using-with-litellm-proxy) |
270
270
 
271
271
  ## Community
272
272
 
@@ -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=JHzYn5SQjWvqEZWixlgmU5X8oFvAzqJf2SdpbNxVVK4,24
9
+ phoenix/version.py,sha256=wTfhUKXJGuW6Cd3BIdlJ2UX7HyglNmvKt33CteybMx8,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
@@ -56,9 +56,9 @@ phoenix/db/types/db_models.py,sha256=nMSd9gWHwObnVO3_slztlHqoeh04czS-Jxu-omS6M6E
56
56
  phoenix/db/types/identifier.py,sha256=Opr3_1di6e5ncrBDn30WfBSr-jN_VGBnkkA4BMuSoyc,244
57
57
  phoenix/db/types/model_provider.py,sha256=zKYGcEQqbAxtPwnq5dL0fYPgDC8nrh_ABLBMR94___4,237
58
58
  phoenix/db/types/token_price_customization.py,sha256=LAb8IwyFJGDCje7CvcPcxNp4NOU8si5hSYaf1fyi624,857
59
- phoenix/db/types/trace_retention.py,sha256=fyqAQCvDiD7mpJ_WUqbPyQvuSdERof4DpKpHLJsdROk,9897
59
+ phoenix/db/types/trace_retention.py,sha256=Y97xfqNa4AO2j6RhhUJIbO6duQ1oX7Vu5bC9laydf1g,9899
60
60
  phoenix/experiments/__init__.py,sha256=6JGwgUd7xCbGpuHqYZlsmErmYvVgv7N_j43bn3dUqsk,123
61
- phoenix/experiments/functions.py,sha256=J9Bfp7ptDB2g6DpSqgf2iw4cDL09P_h4UWAAtJNS9Mg,39971
61
+ phoenix/experiments/functions.py,sha256=7qFTJ2jYXNyXkWvO66RJuCybNVkUdiwxjGtcoPyqhDs,41285
62
62
  phoenix/experiments/tracing.py,sha256=X-wlgbWEzP1oHkLmjop3fGjONo6JK5a0kPXc9YYD014,2856
63
63
  phoenix/experiments/types.py,sha256=O4vvm9WOp0fevTDobStXEJpFKn3acveXgsRClxlnzCM,23477
64
64
  phoenix/experiments/utils.py,sha256=MZ1-OnTcavk_KUtbfGqt55Fk9TGtJpYG_K71WsN-zDk,785
@@ -124,7 +124,7 @@ phoenix/server/api/dataloaders/average_experiment_run_latency.py,sha256=_wEcC47z
124
124
  phoenix/server/api/dataloaders/dataset_example_revisions.py,sha256=xF7M2dg3UmjhdCrscnztCIBBI0cg3RF48IIqvilpc18,4623
125
125
  phoenix/server/api/dataloaders/dataset_example_spans.py,sha256=z_MFquqAcJ9wat7BBp7MVeJ9BYuu2EZEdaog52iWDno,1390
126
126
  phoenix/server/api/dataloaders/document_evaluation_summaries.py,sha256=9fdROnzp-mymggHwNvpRkCk93LUFxxLy55-j3HP_2HY,5565
127
- phoenix/server/api/dataloaders/document_evaluations.py,sha256=W1b7TIlmPG61vR7kEcLZ5hAQYfkSKZAgrJOXYkA9-Ko,1246
127
+ phoenix/server/api/dataloaders/document_evaluations.py,sha256=1bpBDydd-9YvhgkNoE5w-FGrjtnjUztcnjZTdMAazws,1072
128
128
  phoenix/server/api/dataloaders/document_retrieval_metrics.py,sha256=37EcAW7oYQuWYHMDHb0wcqbWj9lhSskvzDO7NJbT5Js,4136
129
129
  phoenix/server/api/dataloaders/experiment_annotation_summaries.py,sha256=CFVj7DwFYj330FLU5w3zEr12AGUX1e8ZX0X5buxMuEk,5643
130
130
  phoenix/server/api/dataloaders/experiment_error_rates.py,sha256=06IZF07qt2y167DBM49QkSNdnphPArhcsgYFcunaL-U,1992
@@ -257,18 +257,18 @@ phoenix/server/api/routers/oauth2.py,sha256=rPcKFvfijzBYLjfwbCNzCn0ihn4wGWh4xh6B
257
257
  phoenix/server/api/routers/utils.py,sha256=M41BoH-fl37izhRuN2aX7lWm7jOC20A_3uClv9TVUUY,583
258
258
  phoenix/server/api/routers/v1/__init__.py,sha256=_CxVCs26dPuC2KygV3VzYqmoAECeFwiSTava9mxIJTE,2790
259
259
  phoenix/server/api/routers/v1/annotation_configs.py,sha256=xp5lJmKYlRsINCUrRD9-lTAElw2v4hdFndS5BWrxICA,16048
260
- phoenix/server/api/routers/v1/annotations.py,sha256=fVl2qeh_ZbWXGvFBTZgeL7aGkkINIScdjuyxnOoSzNM,6817
260
+ phoenix/server/api/routers/v1/annotations.py,sha256=V_Cm_XOJaSVpMsTCfxBd1H39sk17b2y6Lyk5qwwDHvI,11433
261
261
  phoenix/server/api/routers/v1/datasets.py,sha256=9iPORLmbOrPKgUUcRDMs6ZczSIz7hvc6bngJy3IbdR0,38331
262
- phoenix/server/api/routers/v1/documents.py,sha256=D8Pg6lEBHzSuPEDVts__X0ArIKBdQs_3gtIgoZXk_eU,6930
262
+ phoenix/server/api/routers/v1/documents.py,sha256=iA_vYU6_p2-pazh_Rp930kiOsiHYFIPPqsZSSXwPgVI,5733
263
263
  phoenix/server/api/routers/v1/evaluations.py,sha256=aBrPO-xCAWyTxydaHq7W2wQFm65k89uVR-H3VWsd6WQ,13062
264
264
  phoenix/server/api/routers/v1/experiment_evaluations.py,sha256=DZ3UK9OoYKElpRcEER7559-KiAqWr-1IXpZ27FbfP3k,5249
265
- phoenix/server/api/routers/v1/experiment_runs.py,sha256=LZeCQWQIEOZ9jK5Gp_C4JbiYY6AmnnWe85cVcvdkCLE,7107
265
+ phoenix/server/api/routers/v1/experiment_runs.py,sha256=H-WSEFuMSr-pDzP9IMsGktqMHMwMAhen6FSfYYu3ZZg,8372
266
266
  phoenix/server/api/routers/v1/experiments.py,sha256=hIBecGACzGZEgl93ap_JV52pUv-Ij03QJMRxQhBlktI,20611
267
267
  phoenix/server/api/routers/v1/models.py,sha256=p3gJN-9SWiUYTUTft4bZMsZVCBNTb4nN1Foy68eRZzQ,1997
268
268
  phoenix/server/api/routers/v1/projects.py,sha256=XR6uJxHXXtC1q8LNyS9W6iaj440sv1OKCu-OSBfxEys,12824
269
269
  phoenix/server/api/routers/v1/prompts.py,sha256=chRYcLkOYDJdJfVZVukVTUyIRnLPvsJCg41CuPxOIU8,26695
270
- phoenix/server/api/routers/v1/spans.py,sha256=6wu8nUQNp9ma_k5XGvcVx3fq5xPuaN5sbv15ouBWcVc,49438
271
- phoenix/server/api/routers/v1/traces.py,sha256=ur4qVh8NDHDfwXKUNlAQoZhe4xAWe1Dv2ODixR5qroE,11418
270
+ phoenix/server/api/routers/v1/spans.py,sha256=9xWj5RZEGCjOUVCx9bl-tHdQrIS6VvaUROfo3ROg7J4,47583
271
+ phoenix/server/api/routers/v1/traces.py,sha256=-_g-Imy31J_jWyCOMIOAHMEdMB6KxeLRNW56r9-6REI,9849
272
272
  phoenix/server/api/routers/v1/users.py,sha256=eO8zMtGU33Td2_G1l9D7Z0a4CG1CwBUCj_Z9z2uk7wg,12089
273
273
  phoenix/server/api/routers/v1/utils.py,sha256=oXIOGPzPTkE0ZWUTRCoRIQQ7wTzoSwtWFaUSjlGBqts,4960
274
274
  phoenix/server/api/types/Annotation.py,sha256=gsl8CwjIbDUbZRj4d9USwZ_w_Tkz4i7zuZh9ftV80jA,1132
@@ -285,9 +285,10 @@ phoenix/server/api/types/CostBreakdown.py,sha256=yw9dlb0blGIB_dWNP8yEvDHJztHjpiV
285
285
  phoenix/server/api/types/CreateDatasetPayload.py,sha256=R-6zCmuD0f76RU9Giu78xwTHlASQs6Aq8yzvX1Kxc3g,140
286
286
  phoenix/server/api/types/CronExpression.py,sha256=R7oxuSSX_eTUHQWaoaSueQqWDmkkHr5dBKRN6q-6ROk,331
287
287
  phoenix/server/api/types/DataQualityMetric.py,sha256=Aieg3bHeBFaAf4mqeRcH1zT04sXAtQD8ATSHJt7FaBQ,1538
288
- phoenix/server/api/types/Dataset.py,sha256=23dst_glr7kFNC62-q6D9H2hJgrfZnGe7V-Bg72SJgg,15303
288
+ phoenix/server/api/types/Dataset.py,sha256=OvCgbqqNF-bj0iaQldIeEfZiMjyXGFsozIIBsbJJwq4,12648
289
289
  phoenix/server/api/types/DatasetExample.py,sha256=_9byxGpXfYb-hmFMUJeG7Bw1wsRKSJaHwF2IPAbFpFw,3115
290
290
  phoenix/server/api/types/DatasetExampleRevision.py,sha256=c-jWR6dTguEZTm54IMlFr0Ic84I3nefyDnZb7nF5hnI,874
291
+ phoenix/server/api/types/DatasetExperimentAnnotationSummary.py,sha256=EVXz6zfbdYsU5SZ6FUrAA_VQqQCnBE_mbKgmAmFoDLI,195
291
292
  phoenix/server/api/types/DatasetValues.py,sha256=7VbCOLlzOXpZN80-zYF2UGuafRcPsZF-8WQNc0YsKFc,1119
292
293
  phoenix/server/api/types/DatasetVersion.py,sha256=NnDriqQUE20N_Jhyu3-IxHWJQE9wmdHEJIQAKyTVJpo,302
293
294
  phoenix/server/api/types/Dimension.py,sha256=VjW6kOMhFslGSSHlsylpF1hYY3wuhopC2LM2eOcIhRI,10665
@@ -295,11 +296,11 @@ phoenix/server/api/types/DimensionDataType.py,sha256=o0QQRpUzgXbhd10drR2LthxrjB8
295
296
  phoenix/server/api/types/DimensionShape.py,sha256=LNsRt3Uyx1OmwMa5EXk1JGRXPLVV2EEgYXz-6wnLJn4,562
296
297
  phoenix/server/api/types/DimensionType.py,sha256=JLikZUBVqbHlUWcYYd8d60gB1_hmAcuFuZZsjCXpIwc,801
297
298
  phoenix/server/api/types/DimensionWithValue.py,sha256=4_koirnDrZBBdFkIWka2f-OeqZ6IzQXwqz3ccjdgHrc,484
299
+ phoenix/server/api/types/DocumentAnnotation.py,sha256=CMNcODXnKYzAUBITp_iYOoCGpXPEFGnelxmWySqDyn4,3076
298
300
  phoenix/server/api/types/DocumentEvaluationSummary.py,sha256=dx4Btlfw9_XsfmibjfWvMOvUfrvr9oGJq8jYmIL2o-Q,3494
299
301
  phoenix/server/api/types/DocumentRetrievalMetrics.py,sha256=amkpC3H5IU5-9GvO0telpbq00m6lIcv_2v446OpwFwc,1822
300
302
  phoenix/server/api/types/EmbeddingDimension.py,sha256=AYvpZ1nWINAgN4BAZsA_xI_2TNFK6h5jmqzvkPs651M,19428
301
303
  phoenix/server/api/types/EmbeddingMetadata.py,sha256=fJvNNYCbkf3SJalArLy9rcBq9Uj1SNac60zjqe1PFnM,461
302
- phoenix/server/api/types/Evaluation.py,sha256=qkMmq5G9pgwUNOPSTRwR-nNAoqLT3LlXrq7O8cAgXQ8,1356
303
304
  phoenix/server/api/types/EvaluationSummary.py,sha256=vILYejnfPvMwWEXOwhQZsANvYe3AdO2OkMR2rcgp1H4,1512
304
305
  phoenix/server/api/types/Event.py,sha256=iYt_Jx1Roioo0vZ0iPeJTHcTu6NSm4ilVMJ-IMUHAKk,3970
305
306
  phoenix/server/api/types/EventMetadata.py,sha256=-J0tYF9eZTHwCjwxQHY7Gckr2_MNW5OoWT1mydweZNM,635
@@ -338,7 +339,7 @@ phoenix/server/api/types/ScalarDriftMetricEnum.py,sha256=IUAcRPpgL41WdoIgK6cNk2T
338
339
  phoenix/server/api/types/Segments.py,sha256=vT2v0efoa5cuBKxLtxTnsUP5YJJCZfTloM71Spu0tMI,2915
339
340
  phoenix/server/api/types/ServerStatus.py,sha256=t92OHuVhK9DXDk2vsBuHceQNKqYGpHwUp8DNGKz2wOk,88
340
341
  phoenix/server/api/types/SortDir.py,sha256=OUpXhlCzCxPoXSDkJJygEs9Rw9pMymfaZUG5zPTrw4Y,152
341
- phoenix/server/api/types/Span.py,sha256=ag5qWOEbWDCNUAkSUd0K3biE_PuGT2oweL4gVKElNis,32000
342
+ phoenix/server/api/types/Span.py,sha256=wJEEReo38Qsc0nFuBF0LDq9kcfGwmYerA86FXC4GqzE,32130
342
343
  phoenix/server/api/types/SpanAnnotation.py,sha256=uPWu7Z8rmpfKhaaxbged4_o00pPCR3nkn7Gji9vB8jY,1959
343
344
  phoenix/server/api/types/SpanCostDetailSummaryEntry.py,sha256=RXAdOC6MFyR9mwaoj8lMMdI3_9r3z6mR2izJvlsj12U,252
344
345
  phoenix/server/api/types/SpanCostSummary.py,sha256=wo03FCMcFzB5m4P5kvA5jzi9ACLbht38ozQbDJUh94g,357
@@ -350,7 +351,7 @@ phoenix/server/api/types/TokenPrice.py,sha256=OyCZgXCKDIihmDalHvkUDvhvl2Vsxx1J2U
350
351
  phoenix/server/api/types/TokenUsage.py,sha256=aeMPwEDqu8MWT2Jc5sq6Sfb_7kcR_KTzZi6UB9OK7Yg,207
351
352
  phoenix/server/api/types/ToolDefinition.py,sha256=T6UH2vcbuPBDy7jKYOqMth2NdqxMPgDBf11Tpbt5Yb8,187
352
353
  phoenix/server/api/types/Trace.py,sha256=iaSAicxMHTrnUTYxNfMwFMglVeptqu7nF_AHS6k-QGw,9718
353
- phoenix/server/api/types/TraceAnnotation.py,sha256=qUO9DhTIAOKIYqNd5uHqLAsVTsJLSddkXo-gmyjnPBI,1964
354
+ phoenix/server/api/types/TraceAnnotation.py,sha256=NAZ5HXH31x6zjXlh-1CUiXjbiCo0iF6hqIrgts2h3Lo,2022
354
355
  phoenix/server/api/types/UMAPPoints.py,sha256=49sWnxjcAJKRzqUY71Fa0tOPti5XjIIFT5cSg6oNu_U,1650
355
356
  phoenix/server/api/types/User.py,sha256=20q4K_dwWHKdCTLFOmpdbt_OjdGv-98z2dHhwh7RmnI,2412
356
357
  phoenix/server/api/types/UserApiKey.py,sha256=EcsPNxV_PtgpqwA_bPTj_aRYt15l6X24YDy20hUPywU,1251
@@ -364,7 +365,7 @@ phoenix/server/cost_tracking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
364
365
  phoenix/server/cost_tracking/cost_details_calculator.py,sha256=Tt0YcuLhgPuXKWJemWVmYQfG0xQUvH4VziIj6KcDnoA,8945
365
366
  phoenix/server/cost_tracking/cost_model_lookup.py,sha256=jhtVdnQBzrTUHeOGPWgOebk-Io5hpJ1vAgWOu8ojeJ4,6801
366
367
  phoenix/server/cost_tracking/helpers.py,sha256=Pk6ECjnYreTxrldtRwxnwFcxIPVsvDq_yAwDA_spkOc,2122
367
- phoenix/server/cost_tracking/model_cost_manifest.json,sha256=kE8VrBbvdqDy1ijk8KWWs_76U-L_vcRUT5hVT418evY,63488
368
+ phoenix/server/cost_tracking/model_cost_manifest.json,sha256=hOe6WLOd4t99iMCwCVbOya9kERKb7Ci_NR2opiNQY5M,65570
368
369
  phoenix/server/cost_tracking/regex_specificity.py,sha256=9kqWuQ68C-hlwW25hr7BhFlRt5y2Nnpy0Ax3n9UN6Xk,11622
369
370
  phoenix/server/cost_tracking/token_cost_calculator.py,sha256=2JEZnvusx2-xbhp8krp9EarjWuyGH2KO4e-ZwJX-K0s,1598
370
371
  phoenix/server/daemons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -393,10 +394,10 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
393
394
  phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
394
395
  phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
395
396
  phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
396
- phoenix/server/static/.vite/manifest.json,sha256=podIkdilPnaQGOQjbnF7zpOylgP4MXrSImpB5UGvNBc,2328
397
- phoenix/server/static/assets/components-BBwXqJXQ.js,sha256=U8GMAX0TEjXRzhmqCMXjnVaQ9trJDICWTq9IcjqcNhE,664533
398
- phoenix/server/static/assets/index-C_gU3x10.js,sha256=ouZyJslt5vOJGBHCHiO0ziM9Y5lTwAdB86lGFUbr-Ec,63396
399
- phoenix/server/static/assets/pages-YmQb55Uo.js,sha256=tPGWJ9VTxJJSVoyQj_7VutaInS_SuhuXSal0nuJQTKQ,1269456
397
+ phoenix/server/static/.vite/manifest.json,sha256=SftlYsrBTWT-YgHAEYzi01rPZZ4ICS4LX28rKBTiEAs,2328
398
+ phoenix/server/static/assets/components-Cs9c4Nxp.js,sha256=5e_FqxJ4cxQ2lSztbWI9bXdUd0tbXNZjOK_basUj_2s,664533
399
+ phoenix/server/static/assets/index-D1FDMBMV.js,sha256=sZ5WMvooPARvbjfKW_pMVOlJVuqcBI8tTZ8iVUGU4s8,63396
400
+ phoenix/server/static/assets/pages-Cbj9SjBx.js,sha256=Cc1SZLF_HyhwRlxlK_Zsmxmjsb_jFCZeObBG2E6Luns,1272157
400
401
  phoenix/server/static/assets/vendor-CqDb5u4o.css,sha256=zIyFiNJKxMaQk8AvtLgt1rR01oO10d1MFndSDKH9Clw,5517
401
402
  phoenix/server/static/assets/vendor-RdRDaQiR.js,sha256=oTxLetZZXJ20yoKNAYExto9V73y8X5zjddWV46K9CWM,2595492
402
403
  phoenix/server/static/assets/vendor-arizeai-DsYDNOqt.js,sha256=0HIkPJXbKTh85nqphdAXYeStRzdaim0IQxRXiXxa21U,121514
@@ -418,7 +419,7 @@ phoenix/trace/evaluation_conventions.py,sha256=t8jydM3U0-T5YpiQKRJ3tWdWGlHtzKytt
418
419
  phoenix/trace/exporter.py,sha256=bUXh8fjJIbHurrnt4bAm-cCWqUN5FqNsIc8DZzzklkQ,4695
419
420
  phoenix/trace/fixtures.py,sha256=1c7fsyvmxC53Fib9T_Qxp_Ly3OZdDbkLQ0XpFzikEjk,20298
420
421
  phoenix/trace/otel.py,sha256=RJSbAuzS4KBS0t-fntXQaaYwv7FmIXRMrw65DI67z8k,10622
421
- phoenix/trace/projects.py,sha256=9dKv1aiKL4IYMFsg2xnC6EOIRO0YHtkR5o9ALHbMK9g,2178
422
+ phoenix/trace/projects.py,sha256=2wVg_UaNiXuhn60qJhgqJiaQ0OnbOWMnB10QeTGZGwQ,2420
422
423
  phoenix/trace/schemas.py,sha256=Su6e567Bei9oo6PsWO2srTcPAj9C2bMgbGtx64Sgqeg,6332
423
424
  phoenix/trace/span_evaluations.py,sha256=x3nye9r2SQk1mrR3N05YbuWsgUKpMWwTRBtJTDBSj3Y,13156
424
425
  phoenix/trace/span_json_decoder.py,sha256=J1_oDViuUoC4vxPg61U4EOZC1uEMcCzoj-kVjOFEE8k,3224
@@ -443,9 +444,9 @@ phoenix/utilities/project.py,sha256=auVpARXkDb-JgeX5f2aStyFIkeKvGwN9l7qrFeJMVxI,
443
444
  phoenix/utilities/re.py,sha256=6YyUWIkv0zc2SigsxfOWIHzdpjKA_TZo2iqKq7zJKvw,2081
444
445
  phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
445
446
  phoenix/utilities/template_formatters.py,sha256=gh9PJD6WEGw7TEYXfSst1UR4pWWwmjxMLrDVQ_CkpkQ,2779
446
- arize_phoenix-11.30.0.dist-info/METADATA,sha256=p2LDUgcsaZ4l5qRVqP5FVFjrpVpZTvzTN60j913wTtM,31733
447
- arize_phoenix-11.30.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
448
- arize_phoenix-11.30.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
449
- arize_phoenix-11.30.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
450
- arize_phoenix-11.30.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
451
- arize_phoenix-11.30.0.dist-info/RECORD,,
447
+ arize_phoenix-11.32.0.dist-info/METADATA,sha256=l937gONO1AEiuhgulspeCuLVxPdy-gmLrzzd_ZdP0Ms,32877
448
+ arize_phoenix-11.32.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
449
+ arize_phoenix-11.32.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
450
+ arize_phoenix-11.32.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
451
+ arize_phoenix-11.32.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
452
+ arize_phoenix-11.32.0.dist-info/RECORD,,
@@ -199,7 +199,7 @@ class TraceRetentionCronExpression(RootModel[str]):
199
199
 
200
200
  def _parse_field(field: str, min_val: int, max_val: int) -> set[int]:
201
201
  """
202
- Parse a cron field and return the set of matching values.
202
+ Parses a cron field and returns the set of matching values.
203
203
 
204
204
  Args:
205
205
  field (str): The cron field to parse
@@ -109,6 +109,64 @@ def _phoenix_clients() -> tuple[httpx.Client, httpx.AsyncClient]:
109
109
  )
110
110
 
111
111
 
112
+ def _get_all_experiment_runs(
113
+ client: httpx.Client,
114
+ experiment_id: str,
115
+ page_size: int = 50,
116
+ ) -> list[ExperimentRun]:
117
+ """
118
+ Fetch all experiment runs using pagination to handle large datasets.
119
+
120
+ Args:
121
+ client: The HTTP client to use for requests.
122
+ experiment_id: The ID of the experiment.
123
+ page_size: Number of runs to fetch per page. Defaults to 50.
124
+
125
+ Returns:
126
+ List of all experiment runs as ExperimentRun objects.
127
+ """
128
+ all_runs: list[dict[str, Any]] = []
129
+ cursor = None
130
+
131
+ while True:
132
+ params: dict[str, Any] = {"limit": page_size}
133
+ if cursor:
134
+ params["cursor"] = cursor
135
+
136
+ try:
137
+ response = client.get(
138
+ f"v1/experiments/{experiment_id}/runs",
139
+ params=params,
140
+ )
141
+ response.raise_for_status()
142
+ data = response.json()
143
+
144
+ runs = data["data"]
145
+ all_runs.extend(runs)
146
+
147
+ # Check if there are more pages
148
+ cursor = data.get("next_cursor")
149
+ if not cursor:
150
+ break
151
+
152
+ except HTTPStatusError as e:
153
+ if e.response.status_code == 404:
154
+ # Experiment doesn't exist - treat as empty result
155
+ break
156
+ else:
157
+ raise
158
+
159
+ # Convert dicts to ExperimentRun objects
160
+ experiment_runs: list[ExperimentRun] = []
161
+ for run in all_runs:
162
+ # Parse datetime strings
163
+ run["start_time"] = datetime.fromisoformat(run["start_time"])
164
+ run["end_time"] = datetime.fromisoformat(run["end_time"])
165
+ experiment_runs.append(ExperimentRun.from_dict(run))
166
+
167
+ return experiment_runs
168
+
169
+
112
170
  Evaluators: TypeAlias = Union[
113
171
  ExperimentEvaluator,
114
172
  Sequence[ExperimentEvaluator],
@@ -231,7 +289,7 @@ def run_experiment(
231
289
  }
232
290
  if not dry_run:
233
291
  experiment_response = sync_client.post(
234
- f"/v1/datasets/{normalized_dataset.id}/experiments",
292
+ f"v1/datasets/{normalized_dataset.id}/experiments",
235
293
  json=payload,
236
294
  )
237
295
  experiment_response.raise_for_status()
@@ -303,7 +361,7 @@ def run_experiment(
303
361
  try:
304
362
  # Try to create the run directly
305
363
  resp = sync_client.post(
306
- f"/v1/experiments/{experiment.id}/runs", json=jsonify(exp_run)
364
+ f"v1/experiments/{experiment.id}/runs", json=jsonify(exp_run)
307
365
  )
308
366
  resp.raise_for_status()
309
367
  exp_run = replace(exp_run, id=resp.json()["data"]["id"])
@@ -381,7 +439,7 @@ def run_experiment(
381
439
  try:
382
440
  # Try to create the run directly
383
441
  resp = sync_client.post(
384
- f"/v1/experiments/{experiment.id}/runs", json=jsonify(exp_run)
442
+ f"v1/experiments/{experiment.id}/runs", json=jsonify(exp_run)
385
443
  )
386
444
  resp.raise_for_status()
387
445
  exp_run = replace(exp_run, id=resp.json()["data"]["id"])
@@ -420,7 +478,7 @@ def run_experiment(
420
478
  None,
421
479
  functools.partial(
422
480
  sync_client.post,
423
- url=f"/v1/experiments/{experiment.id}/runs",
481
+ url=f"v1/experiments/{experiment.id}/runs",
424
482
  json=jsonify(exp_run),
425
483
  ),
426
484
  )
@@ -498,7 +556,7 @@ def run_experiment(
498
556
  None,
499
557
  functools.partial(
500
558
  sync_client.post,
501
- url=f"/v1/experiments/{experiment.id}/runs",
559
+ url=f"v1/experiments/{experiment.id}/runs",
502
560
  json=jsonify(exp_run),
503
561
  ),
504
562
  )
@@ -548,13 +606,7 @@ def run_experiment(
548
606
 
549
607
  # Get the final state of runs from the database
550
608
  if not dry_run:
551
- all_runs = sync_client.get(f"/v1/experiments/{experiment.id}/runs").json()["data"]
552
- task_runs = []
553
- for run in all_runs:
554
- # Parse datetime strings
555
- run["start_time"] = datetime.fromisoformat(run["start_time"])
556
- run["end_time"] = datetime.fromisoformat(run["end_time"])
557
- task_runs.append(ExperimentRun.from_dict(run))
609
+ task_runs = _get_all_experiment_runs(sync_client, experiment.id)
558
610
 
559
611
  # Check if we got all expected runs
560
612
  expected_runs = len(normalized_dataset.examples) * repetitions
@@ -613,16 +665,14 @@ def evaluate_experiment(
613
665
  else:
614
666
  dataset = Dataset.from_dict(
615
667
  sync_client.get(
616
- f"/v1/datasets/{dataset_id}/examples",
668
+ f"v1/datasets/{dataset_id}/examples",
617
669
  params={"version_id": str(dataset_version_id)},
618
670
  ).json()["data"]
619
671
  )
620
672
  if not dataset.examples:
621
673
  raise ValueError(f"Dataset has no examples: {dataset_id=}, {dataset_version_id=}")
622
- experiment_runs = {
623
- exp_run["id"]: ExperimentRun.from_dict(exp_run)
624
- for exp_run in sync_client.get(f"/v1/experiments/{experiment.id}/runs").json()["data"]
625
- }
674
+ all_runs = _get_all_experiment_runs(sync_client, experiment.id)
675
+ experiment_runs = {exp_run.id: exp_run for exp_run in all_runs}
626
676
  if not experiment_runs:
627
677
  raise ValueError("Experiment has not been run")
628
678
  params = ExperimentParameters(n_examples=len(dataset.examples))
@@ -715,7 +765,7 @@ def evaluate_experiment(
715
765
  trace_id=_str_trace_id(span.get_span_context().trace_id), # type: ignore[no-untyped-call]
716
766
  )
717
767
  if not dry_run:
718
- resp = sync_client.post("/v1/experiment_evaluations", json=jsonify(eval_run))
768
+ resp = sync_client.post("v1/experiment_evaluations", json=jsonify(eval_run))
719
769
  resp.raise_for_status()
720
770
  eval_run = replace(eval_run, id=resp.json()["data"]["id"])
721
771
  return eval_run
@@ -777,7 +827,7 @@ def evaluate_experiment(
777
827
  None,
778
828
  functools.partial(
779
829
  sync_client.post,
780
- url="/v1/experiment_evaluations",
830
+ url="v1/experiment_evaluations",
781
831
  json=jsonify(eval_run),
782
832
  ),
783
833
  )
@@ -5,11 +5,10 @@ from strawberry.dataloader import DataLoader
5
5
  from typing_extensions import TypeAlias
6
6
 
7
7
  from phoenix.db import models
8
- from phoenix.server.api.types.Evaluation import DocumentAnnotation
9
8
  from phoenix.server.types import DbSessionFactory
10
9
 
11
10
  Key: TypeAlias = int
12
- Result: TypeAlias = list[DocumentAnnotation]
11
+ Result: TypeAlias = list[models.DocumentAnnotation]
13
12
 
14
13
 
15
14
  class DocumentEvaluationsDataLoader(DataLoader[Key, Result]):
@@ -18,14 +17,12 @@ class DocumentEvaluationsDataLoader(DataLoader[Key, Result]):
18
17
  self._db = db
19
18
 
20
19
  async def _load_fn(self, keys: list[Key]) -> list[Result]:
21
- document_evaluations_by_id: defaultdict[Key, Result] = defaultdict(list)
20
+ document_annotations_by_id: defaultdict[Key, Result] = defaultdict(list)
22
21
  mda = models.DocumentAnnotation
23
22
  async with self._db() as session:
24
- data = await session.stream_scalars(
25
- select(mda).where(mda.span_rowid.in_(keys)).where(mda.annotator_kind == "LLM")
26
- )
23
+ data = await session.stream_scalars(select(mda).where(mda.span_rowid.in_(keys)))
27
24
  async for document_evaluation in data:
28
- document_evaluations_by_id[document_evaluation.span_rowid].append(
29
- DocumentAnnotation.from_sql_document_annotation(document_evaluation)
25
+ document_annotations_by_id[document_evaluation.span_rowid].append(
26
+ document_evaluation
30
27
  )
31
- return [document_evaluations_by_id[key] for key in keys]
28
+ return [document_annotations_by_id[key] for key in keys]
@@ -1,32 +1,38 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- from datetime import datetime
5
- from typing import Literal, Optional
4
+ from datetime import datetime, timezone
5
+ from typing import Any, Literal, Optional
6
6
 
7
7
  from fastapi import APIRouter, HTTPException, Path, Query
8
+ from pydantic import Field
8
9
  from sqlalchemy import exists, select
9
10
  from starlette.requests import Request
10
11
  from starlette.status import HTTP_200_OK, HTTP_404_NOT_FOUND, HTTP_422_UNPROCESSABLE_ENTITY
11
12
  from strawberry.relay import GlobalID
12
13
 
13
14
  from phoenix.db import models
15
+ from phoenix.db.insertion.types import Precursors
16
+ from phoenix.server.api.routers.v1.models import V1RoutesBaseModel
14
17
  from phoenix.server.api.types.SpanAnnotation import SpanAnnotation as SpanAnnotationNodeType
18
+ from phoenix.server.api.types.TraceAnnotation import TraceAnnotation as TraceAnnotationNodeType
15
19
  from phoenix.server.api.types.User import User as UserNodeType
16
20
 
17
- from .spans import SpanAnnotationData, SpanAnnotationResult
18
21
  from .utils import PaginatedResponseBody, _get_project_by_identifier, add_errors_to_responses
19
22
 
20
23
  logger = logging.getLogger(__name__)
21
24
 
22
25
  SPAN_ANNOTATION_NODE_NAME = SpanAnnotationNodeType.__name__
26
+ TRACE_ANNOTATION_NODE_NAME = TraceAnnotationNodeType.__name__
27
+ MAX_TRACE_IDS = 1_000
23
28
  USER_NODE_NAME = UserNodeType.__name__
24
29
  MAX_SPAN_IDS = 1_000
30
+ MAX_SESSION_IDS = 1_000
25
31
 
26
32
  router = APIRouter(tags=["annotations"])
27
33
 
28
34
 
29
- class SpanAnnotation(SpanAnnotationData):
35
+ class Annotation(V1RoutesBaseModel):
30
36
  id: str
31
37
  created_at: datetime
32
38
  updated_at: datetime
@@ -34,10 +40,127 @@ class SpanAnnotation(SpanAnnotationData):
34
40
  user_id: Optional[str]
35
41
 
36
42
 
43
+ class AnnotationResult(V1RoutesBaseModel):
44
+ label: Optional[str] = Field(default=None, description="The label assigned by the annotation")
45
+ score: Optional[float] = Field(default=None, description="The score assigned by the annotation")
46
+ explanation: Optional[str] = Field(
47
+ default=None, description="Explanation of the annotation result"
48
+ )
49
+
50
+
51
+ class AnnotationData(V1RoutesBaseModel):
52
+ name: str = Field(description="The name of the annotation")
53
+ annotator_kind: Literal["LLM", "CODE", "HUMAN"] = Field(
54
+ description="The kind of annotator used for the annotation"
55
+ )
56
+ result: Optional[AnnotationResult] = Field(
57
+ default=None, description="The result of the annotation"
58
+ )
59
+ metadata: Optional[dict[str, Any]] = Field(
60
+ default=None, description="Metadata for the annotation"
61
+ )
62
+ identifier: str = Field(
63
+ default="",
64
+ description=(
65
+ "The identifier of the annotation. "
66
+ "If provided, the annotation will be updated if it already exists."
67
+ ),
68
+ )
69
+
70
+
71
+ class SpanAnnotationData(AnnotationData):
72
+ span_id: str = Field(description="OpenTelemetry Span ID (hex format w/o 0x prefix)")
73
+
74
+ def as_precursor(self, *, user_id: Optional[int] = None) -> Precursors.SpanAnnotation:
75
+ return Precursors.SpanAnnotation(
76
+ datetime.now(timezone.utc),
77
+ self.span_id,
78
+ models.SpanAnnotation(
79
+ name=self.name,
80
+ annotator_kind=self.annotator_kind,
81
+ score=self.result.score if self.result else None,
82
+ label=self.result.label if self.result else None,
83
+ explanation=self.result.explanation if self.result else None,
84
+ metadata_=self.metadata or {},
85
+ identifier=self.identifier,
86
+ source="API",
87
+ user_id=user_id,
88
+ ),
89
+ )
90
+
91
+
92
+ class SpanAnnotation(SpanAnnotationData, Annotation):
93
+ pass
94
+
95
+
37
96
  class SpanAnnotationsResponseBody(PaginatedResponseBody[SpanAnnotation]):
38
97
  pass
39
98
 
40
99
 
100
+ class SpanDocumentAnnotationData(AnnotationData):
101
+ span_id: str = Field(description="OpenTelemetry Span ID (hex format w/o 0x prefix)")
102
+ document_position: int = Field(
103
+ description="A 0 based index of the document. E.x. the first document during retrieval is 0"
104
+ )
105
+
106
+ # Precursor here means a value to add to a queue for processing async
107
+ def as_precursor(self, *, user_id: Optional[int] = None) -> Precursors.DocumentAnnotation:
108
+ return Precursors.DocumentAnnotation(
109
+ datetime.now(timezone.utc),
110
+ self.span_id,
111
+ self.document_position,
112
+ models.DocumentAnnotation(
113
+ name=self.name,
114
+ annotator_kind=self.annotator_kind,
115
+ document_position=self.document_position,
116
+ score=self.result.score if self.result else None,
117
+ label=self.result.label if self.result else None,
118
+ explanation=self.result.explanation if self.result else None,
119
+ metadata_=self.metadata or {},
120
+ identifier=self.identifier,
121
+ source="API",
122
+ user_id=user_id,
123
+ ),
124
+ )
125
+
126
+
127
+ class SpanDocumentAnnotation(SpanDocumentAnnotationData, Annotation):
128
+ pass
129
+
130
+
131
+ class SpanDocumentAnnotationsResponseBody(PaginatedResponseBody[SpanDocumentAnnotation]):
132
+ pass
133
+
134
+
135
+ class TraceAnnotationData(AnnotationData):
136
+ trace_id: str = Field(description="OpenTelemetry Trace ID (hex format w/o 0x prefix)")
137
+
138
+ def as_precursor(self, *, user_id: Optional[int] = None) -> Precursors.TraceAnnotation:
139
+ return Precursors.TraceAnnotation(
140
+ datetime.now(timezone.utc),
141
+ self.trace_id,
142
+ models.TraceAnnotation(
143
+ name=self.name,
144
+ annotator_kind=self.annotator_kind,
145
+ score=self.result.score if self.result else None,
146
+ label=self.result.label if self.result else None,
147
+ explanation=self.result.explanation if self.result else None,
148
+ metadata_=self.metadata or {},
149
+ identifier=self.identifier,
150
+ source="API",
151
+ user_id=user_id,
152
+ ),
153
+ )
154
+
155
+
156
+ class TraceAnnotation(TraceAnnotationData, Annotation):
157
+ pass
158
+
159
+
160
+ class TraceAnnotationsResponseBody(PaginatedResponseBody[TraceAnnotation]):
161
+ pass
162
+
163
+
41
164
  @router.get(
42
165
  "/projects/{project_identifier}/span_annotations",
43
166
  operation_id="listSpanAnnotationsBySpanIds",
@@ -164,7 +287,7 @@ async def list_span_annotations(
164
287
  id=str(GlobalID(SPAN_ANNOTATION_NODE_NAME, str(anno.id))),
165
288
  span_id=span_id,
166
289
  name=anno.name,
167
- result=SpanAnnotationResult(
290
+ result=AnnotationResult(
168
291
  label=anno.label,
169
292
  score=anno.score,
170
293
  explanation=anno.explanation,