arize-phoenix 11.15.0__py3-none-any.whl → 11.16.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arize-phoenix might be problematic. Click here for more details.
- {arize_phoenix-11.15.0.dist-info → arize_phoenix-11.16.0.dist-info}/METADATA +1 -1
- {arize_phoenix-11.15.0.dist-info → arize_phoenix-11.16.0.dist-info}/RECORD +11 -11
- phoenix/db/models.py +35 -0
- phoenix/server/api/routers/v1/traces.py +52 -3
- phoenix/server/api/types/Project.py +2 -2
- phoenix/server/dml_event_handler.py +4 -0
- phoenix/version.py +1 -1
- {arize_phoenix-11.15.0.dist-info → arize_phoenix-11.16.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-11.15.0.dist-info → arize_phoenix-11.16.0.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-11.15.0.dist-info → arize_phoenix-11.16.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-11.15.0.dist-info → arize_phoenix-11.16.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,7 +6,7 @@ phoenix/exceptions.py,sha256=n2L2KKuecrdflB9MsCdAYCiSEvGJptIsfRkXMoJle7A,169
|
|
|
6
6
|
phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
7
7
|
phoenix/services.py,sha256=ngkyKGVatX3cO2WJdo2hKdaVKP-xJCMvqthvga6kJss,5196
|
|
8
8
|
phoenix/settings.py,sha256=2kHfT3BNOVd4dAO1bq-syEQbHSG8oX2-7NhOwK2QREk,896
|
|
9
|
-
phoenix/version.py,sha256=
|
|
9
|
+
phoenix/version.py,sha256=1jPwVRFknFjr1Z2-4KMQGv_ONw2Eybch5xZM1zNP1rg,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
|
|
@@ -22,7 +22,7 @@ phoenix/db/enums.py,sha256=w3O5YuJEEzVTwVDZb8b2UUFhU8yK_GosF081VVrrno0,188
|
|
|
22
22
|
phoenix/db/facilitator.py,sha256=aRbkIJkIDP2zMsLKbO7Y8jJq4U2HbV7Lf6GYVWXVImU,20151
|
|
23
23
|
phoenix/db/helpers.py,sha256=dsGONSgkhmVtjMpJh-84KRVTf5uPdQ5c8O2AhUgHkRg,14150
|
|
24
24
|
phoenix/db/migrate.py,sha256=oUrXH8yEbcpL4eh09aSCuUiSrhFli0eT5D_j4ZmYChY,2797
|
|
25
|
-
phoenix/db/models.py,sha256=
|
|
25
|
+
phoenix/db/models.py,sha256=bxyBRSST8rqBKcAyPyyDHmkv9AadaE3XmQnpcaMvvnk,61588
|
|
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
|
|
@@ -95,7 +95,7 @@ phoenix/server/app.py,sha256=00un2qg4eUmHr37TtZlccmPgRnI1D5FB5r2zwIfI9W4,48047
|
|
|
95
95
|
phoenix/server/authorization.py,sha256=OxROn7ibpKtCTrcgDkzWuNxVaQcSQ8MAx7zbjZiliK0,3201
|
|
96
96
|
phoenix/server/bearer_auth.py,sha256=f4v4W94KyTdGGCPsK1tXOe0vouPuvanAEa03XSdCvPE,6650
|
|
97
97
|
phoenix/server/dml_event.py,sha256=8UciN7W8X_IqQfAnAeAh68BezNmfxSxuTeD6IUerTW8,2911
|
|
98
|
-
phoenix/server/dml_event_handler.py,sha256=
|
|
98
|
+
phoenix/server/dml_event_handler.py,sha256=71_iPcHiJ4E-8Z7sGL2j0vx_RpkmcMVEUFIBsWrdp-E,8483
|
|
99
99
|
phoenix/server/grpc_server.py,sha256=ahHC394gFZYM3h4FmjQxZwL-a4x3mWmV2EdXYFlNEC8,4676
|
|
100
100
|
phoenix/server/jwt_store.py,sha256=B6uVildN_dQDTG_-aHHvuVSI7wIVK1yvED-_y6se2GU,16905
|
|
101
101
|
phoenix/server/main.py,sha256=UBwxrQIEE7ci-SbE6GAlRYmbMHooI6JYG6sG-UpBFFs,18905
|
|
@@ -266,7 +266,7 @@ phoenix/server/api/routers/v1/models.py,sha256=p3gJN-9SWiUYTUTft4bZMsZVCBNTb4nN1
|
|
|
266
266
|
phoenix/server/api/routers/v1/projects.py,sha256=32GwTLsaFgQLVNdjrlrGe90XT3pIX1N7-zX9D9_J_4w,12701
|
|
267
267
|
phoenix/server/api/routers/v1/prompts.py,sha256=chRYcLkOYDJdJfVZVukVTUyIRnLPvsJCg41CuPxOIU8,26695
|
|
268
268
|
phoenix/server/api/routers/v1/spans.py,sha256=ETH6I14O_zY9IW69Fo-LxL796BR3xgt8qdzwqzYAvbE,44208
|
|
269
|
-
phoenix/server/api/routers/v1/traces.py,sha256=
|
|
269
|
+
phoenix/server/api/routers/v1/traces.py,sha256=uLASCHMgU13tUhuWXnXqaom1crrQVpXi9PUtsyDXU9Y,10318
|
|
270
270
|
phoenix/server/api/routers/v1/users.py,sha256=hUZCe7ctJqEkSJBe046a0OAFMLZodtyO7NLP7U6S8Pg,11986
|
|
271
271
|
phoenix/server/api/routers/v1/utils.py,sha256=oXIOGPzPTkE0ZWUTRCoRIQQ7wTzoSwtWFaUSjlGBqts,4960
|
|
272
272
|
phoenix/server/api/types/Annotation.py,sha256=gsl8CwjIbDUbZRj4d9USwZ_w_Tkz4i7zuZh9ftV80jA,1132
|
|
@@ -321,7 +321,7 @@ phoenix/server/api/types/ModelInterface.py,sha256=Qe7H23wDb_Q2-HmeY2t0R5Jsn4aAfY
|
|
|
321
321
|
phoenix/server/api/types/NumericRange.py,sha256=afEjgF97Go_OvmjMggbPBt-zGM8IONewAyEiKEHRds0,192
|
|
322
322
|
phoenix/server/api/types/PerformanceMetric.py,sha256=KFkmJDqP43eDUtARQOUqR7NYcxvL6Vh2uisHWU6H3ko,387
|
|
323
323
|
phoenix/server/api/types/PlaygroundModel.py,sha256=IqJFxsAAJMRyaFI9ryI3GQrpFOJ5Llf6kIutEO-tFvM,321
|
|
324
|
-
phoenix/server/api/types/Project.py,sha256=
|
|
324
|
+
phoenix/server/api/types/Project.py,sha256=AxKlA7FHlI48uRKx5-MRzMzEyyWPZPffX_iZOV0jeJs,69652
|
|
325
325
|
phoenix/server/api/types/ProjectSession.py,sha256=uwqTsDTfSGz13AvP-cwS_mJR5JZ1lHqu10ungbl7g5s,6245
|
|
326
326
|
phoenix/server/api/types/ProjectTraceRetentionPolicy.py,sha256=tYy2kgalPDyuaYZr0VUHjH0YpXaiF_QOzg5yfaV_c7c,3782
|
|
327
327
|
phoenix/server/api/types/Prompt.py,sha256=ccP4eq1e38xbF0afclGWLOuDpBVpNbJ3AOSRClF8yFQ,4955
|
|
@@ -439,9 +439,9 @@ phoenix/utilities/project.py,sha256=auVpARXkDb-JgeX5f2aStyFIkeKvGwN9l7qrFeJMVxI,
|
|
|
439
439
|
phoenix/utilities/re.py,sha256=6YyUWIkv0zc2SigsxfOWIHzdpjKA_TZo2iqKq7zJKvw,2081
|
|
440
440
|
phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
441
441
|
phoenix/utilities/template_formatters.py,sha256=gh9PJD6WEGw7TEYXfSst1UR4pWWwmjxMLrDVQ_CkpkQ,2779
|
|
442
|
-
arize_phoenix-11.
|
|
443
|
-
arize_phoenix-11.
|
|
444
|
-
arize_phoenix-11.
|
|
445
|
-
arize_phoenix-11.
|
|
446
|
-
arize_phoenix-11.
|
|
447
|
-
arize_phoenix-11.
|
|
442
|
+
arize_phoenix-11.16.0.dist-info/METADATA,sha256=Vhoaw8m0XPZKoPzmUJxOrEfcQ-UZhTdIGXceg5fEiuU,30851
|
|
443
|
+
arize_phoenix-11.16.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
444
|
+
arize_phoenix-11.16.0.dist-info/entry_points.txt,sha256=Pgpn8Upxx9P8z8joPXZWl2LlnAlGc3gcQoVchb06X1Q,94
|
|
445
|
+
arize_phoenix-11.16.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
|
|
446
|
+
arize_phoenix-11.16.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
|
|
447
|
+
arize_phoenix-11.16.0.dist-info/RECORD,,
|
phoenix/db/models.py
CHANGED
|
@@ -841,6 +841,41 @@ def _(element: Any, compiler: Any, **kw: Any) -> Any:
|
|
|
841
841
|
return compiler.process(func.text_contains(string, substring) > 0, **kw)
|
|
842
842
|
|
|
843
843
|
|
|
844
|
+
class CaseInsensitiveContains(expression.FunctionElement[bool]):
|
|
845
|
+
# See https://docs.sqlalchemy.org/en/20/core/compiler.html
|
|
846
|
+
inherit_cache = True
|
|
847
|
+
type = Boolean()
|
|
848
|
+
name = "case_insensitive_contains"
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
@compiles(CaseInsensitiveContains)
|
|
852
|
+
def _(element: Any, compiler: Any, **kw: Any) -> Any:
|
|
853
|
+
string, substring = list(element.clauses)
|
|
854
|
+
result = compiler.process(func.lower(string).contains(func.lower(substring)), **kw)
|
|
855
|
+
return result
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
@compiles(CaseInsensitiveContains, "postgresql")
|
|
859
|
+
def _(element: Any, compiler: Any, **kw: Any) -> Any:
|
|
860
|
+
string, substring = list(element.clauses)
|
|
861
|
+
escaped = func.replace(
|
|
862
|
+
func.replace(func.replace(substring, "\\", "\\\\"), "%", "\\%"), "_", "\\_"
|
|
863
|
+
)
|
|
864
|
+
pattern = func.concat("%", escaped, "%")
|
|
865
|
+
result = compiler.process(string.ilike(pattern), **kw)
|
|
866
|
+
return result
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
@compiles(CaseInsensitiveContains, "sqlite")
|
|
870
|
+
def _(element: Any, compiler: Any, **kw: Any) -> Any:
|
|
871
|
+
# Use sqlean's `text_lower` to handle non-ASCII characters
|
|
872
|
+
string, substring = list(element.clauses)
|
|
873
|
+
result = compiler.process(
|
|
874
|
+
func.text_contains(func.text_lower(string), func.text_lower(substring)), **kw
|
|
875
|
+
)
|
|
876
|
+
return result
|
|
877
|
+
|
|
878
|
+
|
|
844
879
|
async def init_models(engine: AsyncEngine) -> None:
|
|
845
880
|
async with engine.begin() as conn:
|
|
846
881
|
await conn.run_sync(Base.metadata.create_all)
|
|
@@ -2,14 +2,14 @@ import gzip
|
|
|
2
2
|
import zlib
|
|
3
3
|
from typing import Any, Literal, Optional
|
|
4
4
|
|
|
5
|
-
from fastapi import APIRouter, BackgroundTasks, Depends, Header, HTTPException, Query
|
|
5
|
+
from fastapi import APIRouter, BackgroundTasks, Depends, Header, HTTPException, Path, Query
|
|
6
6
|
from google.protobuf.message import DecodeError
|
|
7
7
|
from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import (
|
|
8
8
|
ExportTraceServiceRequest,
|
|
9
9
|
ExportTraceServiceResponse,
|
|
10
10
|
)
|
|
11
11
|
from pydantic import Field
|
|
12
|
-
from sqlalchemy import insert, select
|
|
12
|
+
from sqlalchemy import delete, insert, select
|
|
13
13
|
from starlette.concurrency import run_in_threadpool
|
|
14
14
|
from starlette.datastructures import State
|
|
15
15
|
from starlette.requests import Request
|
|
@@ -26,7 +26,7 @@ from phoenix.db.insertion.helpers import as_kv
|
|
|
26
26
|
from phoenix.db.insertion.types import Precursors
|
|
27
27
|
from phoenix.server.authorization import is_not_locked
|
|
28
28
|
from phoenix.server.bearer_auth import PhoenixUser
|
|
29
|
-
from phoenix.server.dml_event import TraceAnnotationInsertEvent
|
|
29
|
+
from phoenix.server.dml_event import SpanDeleteEvent, TraceAnnotationInsertEvent
|
|
30
30
|
from phoenix.trace.otel import decode_otlp_span
|
|
31
31
|
from phoenix.utilities.project import get_project_name
|
|
32
32
|
|
|
@@ -225,3 +225,52 @@ async def _add_spans(req: ExportTraceServiceRequest, state: State) -> None:
|
|
|
225
225
|
for otlp_span in scope_span.spans:
|
|
226
226
|
span = await run_in_threadpool(decode_otlp_span, otlp_span)
|
|
227
227
|
await state.queue_span_for_bulk_insert(span, project_name)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@router.delete(
|
|
231
|
+
"/traces/{trace_id}",
|
|
232
|
+
operation_id="deleteTrace",
|
|
233
|
+
summary="Delete a trace by trace_id",
|
|
234
|
+
description=(
|
|
235
|
+
"Delete an entire trace by its OpenTelemetry trace_id. "
|
|
236
|
+
"This will permanently remove all spans in the trace and their associated data."
|
|
237
|
+
),
|
|
238
|
+
responses=add_errors_to_responses([HTTP_404_NOT_FOUND]),
|
|
239
|
+
status_code=204, # No Content for successful deletion
|
|
240
|
+
)
|
|
241
|
+
async def delete_trace(
|
|
242
|
+
request: Request,
|
|
243
|
+
trace_id: str = Path(description="The OpenTelemetry trace_id of the trace to delete"),
|
|
244
|
+
) -> None:
|
|
245
|
+
"""
|
|
246
|
+
Delete a trace by trace_id.
|
|
247
|
+
|
|
248
|
+
This endpoint will:
|
|
249
|
+
1. Find and delete the trace with the given trace_id (and all its spans via CASCADE)
|
|
250
|
+
2. Trigger cache invalidation events
|
|
251
|
+
3. Return 204 No Content on success
|
|
252
|
+
|
|
253
|
+
Note: This deletes the entire trace, including all spans, which maintains data consistency
|
|
254
|
+
and avoids orphaned spans or inconsistent cached cumulative fields.
|
|
255
|
+
"""
|
|
256
|
+
async with request.app.state.db() as session:
|
|
257
|
+
# Delete the trace directly and get project_id for cache invalidation
|
|
258
|
+
delete_stmt = (
|
|
259
|
+
delete(models.Trace)
|
|
260
|
+
.where(models.Trace.trace_id == trace_id)
|
|
261
|
+
.returning(models.Trace.project_rowid)
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
project_id = await session.scalar(delete_stmt)
|
|
265
|
+
|
|
266
|
+
if project_id is None:
|
|
267
|
+
raise HTTPException(
|
|
268
|
+
status_code=HTTP_404_NOT_FOUND,
|
|
269
|
+
detail=f"Trace with trace_id '{trace_id}' not found",
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
# Trigger cache invalidation event
|
|
273
|
+
request.state.event_queue.put(SpanDeleteEvent((project_id,)))
|
|
274
|
+
|
|
275
|
+
# Return 204 No Content (successful deletion with no response body)
|
|
276
|
+
return None
|
|
@@ -404,11 +404,11 @@ class Project(Node):
|
|
|
404
404
|
.where(models.Span.parent_id.is_(None))
|
|
405
405
|
.where(
|
|
406
406
|
or_(
|
|
407
|
-
models.
|
|
407
|
+
models.CaseInsensitiveContains(
|
|
408
408
|
models.Span.attributes[INPUT_VALUE].as_string(),
|
|
409
409
|
filter_io_substring,
|
|
410
410
|
),
|
|
411
|
-
models.
|
|
411
|
+
models.CaseInsensitiveContains(
|
|
412
412
|
models.Span.attributes[OUTPUT_VALUE].as_string(),
|
|
413
413
|
filter_io_substring,
|
|
414
414
|
),
|
|
@@ -128,6 +128,10 @@ class _SpanDmlEventHandler(_DmlEventHandler[SpanDmlEvent]):
|
|
|
128
128
|
class _SpanDeleteEventHandler(_SpanDmlEventHandler):
|
|
129
129
|
@staticmethod
|
|
130
130
|
def _clear(cache: CacheForDataLoaders, project_id: int) -> None:
|
|
131
|
+
# Call parent's cache invalidation first (core span caches)
|
|
132
|
+
_SpanDmlEventHandler._clear(cache, project_id)
|
|
133
|
+
|
|
134
|
+
# Then invalidate annotation-specific caches
|
|
131
135
|
cache.annotation_summary.invalidate_project(project_id)
|
|
132
136
|
cache.document_evaluation_summary.invalidate_project(project_id)
|
|
133
137
|
|
phoenix/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "11.
|
|
1
|
+
__version__ = "11.16.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|