arize-phoenix 4.35.2__py3-none-any.whl → 5.0.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-4.35.2.dist-info → arize_phoenix-5.0.0.dist-info}/METADATA +10 -12
- {arize_phoenix-4.35.2.dist-info → arize_phoenix-5.0.0.dist-info}/RECORD +92 -79
- phoenix/__init__.py +86 -0
- phoenix/auth.py +275 -14
- phoenix/config.py +369 -27
- phoenix/db/alembic.ini +0 -34
- phoenix/db/engines.py +27 -10
- phoenix/db/enums.py +20 -0
- phoenix/db/facilitator.py +112 -0
- phoenix/db/insertion/dataset.py +0 -1
- phoenix/db/insertion/types.py +1 -1
- phoenix/db/migrate.py +3 -3
- phoenix/db/migrations/env.py +0 -7
- phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py +157 -0
- phoenix/db/models.py +145 -60
- phoenix/experiments/evaluators/code_evaluators.py +9 -3
- phoenix/experiments/functions.py +1 -4
- phoenix/inferences/fixtures.py +0 -1
- phoenix/inferences/inferences.py +0 -1
- phoenix/logging/__init__.py +3 -0
- phoenix/logging/_config.py +90 -0
- phoenix/logging/_filter.py +6 -0
- phoenix/logging/_formatter.py +69 -0
- phoenix/metrics/__init__.py +0 -1
- phoenix/otel/settings.py +4 -4
- phoenix/server/api/README.md +28 -0
- phoenix/server/api/auth.py +32 -0
- phoenix/server/api/context.py +50 -2
- phoenix/server/api/dataloaders/__init__.py +4 -0
- phoenix/server/api/dataloaders/user_roles.py +30 -0
- phoenix/server/api/dataloaders/users.py +33 -0
- phoenix/server/api/exceptions.py +7 -0
- phoenix/server/api/mutations/__init__.py +0 -2
- phoenix/server/api/mutations/api_key_mutations.py +104 -86
- phoenix/server/api/mutations/dataset_mutations.py +8 -8
- phoenix/server/api/mutations/experiment_mutations.py +2 -2
- phoenix/server/api/mutations/export_events_mutations.py +3 -3
- phoenix/server/api/mutations/project_mutations.py +3 -3
- phoenix/server/api/mutations/span_annotations_mutations.py +4 -4
- phoenix/server/api/mutations/trace_annotations_mutations.py +4 -4
- phoenix/server/api/mutations/user_mutations.py +282 -42
- phoenix/server/api/openapi/schema.py +2 -2
- phoenix/server/api/queries.py +48 -39
- phoenix/server/api/routers/__init__.py +11 -0
- phoenix/server/api/routers/auth.py +284 -0
- phoenix/server/api/routers/embeddings.py +26 -0
- phoenix/server/api/routers/oauth2.py +456 -0
- phoenix/server/api/routers/v1/__init__.py +38 -16
- phoenix/server/api/routers/v1/datasets.py +0 -1
- phoenix/server/api/types/ApiKey.py +11 -0
- phoenix/server/api/types/AuthMethod.py +9 -0
- phoenix/server/api/types/User.py +48 -4
- phoenix/server/api/types/UserApiKey.py +35 -1
- phoenix/server/api/types/UserRole.py +7 -0
- phoenix/server/app.py +105 -34
- phoenix/server/bearer_auth.py +161 -0
- phoenix/server/email/__init__.py +0 -0
- phoenix/server/email/sender.py +26 -0
- phoenix/server/email/templates/__init__.py +0 -0
- phoenix/server/email/templates/password_reset.html +19 -0
- phoenix/server/email/types.py +11 -0
- phoenix/server/grpc_server.py +6 -0
- phoenix/server/jwt_store.py +504 -0
- phoenix/server/main.py +61 -30
- phoenix/server/oauth2.py +51 -0
- phoenix/server/prometheus.py +20 -0
- phoenix/server/rate_limiters.py +191 -0
- phoenix/server/static/.vite/manifest.json +31 -31
- phoenix/server/static/assets/{components-Dte7_KRd.js → components-REunxTt6.js} +348 -286
- phoenix/server/static/assets/index-DAPJxlCw.js +101 -0
- phoenix/server/static/assets/{pages-CnTvEGEN.js → pages-1VrMk2pW.js} +559 -291
- phoenix/server/static/assets/{vendor-BC3OPQuM.js → vendor-B5IC0ivG.js} +5 -5
- phoenix/server/static/assets/{vendor-arizeai-NjB3cZzD.js → vendor-arizeai-aFbT4kl1.js} +2 -2
- phoenix/server/static/assets/{vendor-codemirror-gE_JCOgX.js → vendor-codemirror-BEGorXSV.js} +1 -1
- phoenix/server/static/assets/{vendor-recharts-BXLYwcXF.js → vendor-recharts-6nUU7gU_.js} +1 -1
- phoenix/server/telemetry.py +2 -2
- phoenix/server/templates/index.html +1 -0
- phoenix/server/types.py +157 -1
- phoenix/services.py +0 -1
- phoenix/session/client.py +7 -3
- phoenix/session/evaluation.py +0 -1
- phoenix/session/session.py +0 -1
- phoenix/settings.py +9 -0
- phoenix/trace/exporter.py +0 -1
- phoenix/trace/fixtures.py +0 -2
- phoenix/utilities/client.py +16 -0
- phoenix/utilities/logging.py +9 -1
- phoenix/utilities/re.py +3 -3
- phoenix/version.py +1 -1
- phoenix/db/migrations/future_versions/README.md +0 -4
- phoenix/db/migrations/future_versions/cd164e83824f_users_and_tokens.py +0 -293
- phoenix/db/migrations/versions/.gitignore +0 -1
- phoenix/server/api/mutations/auth.py +0 -18
- phoenix/server/api/mutations/auth_mutations.py +0 -65
- phoenix/server/static/assets/index-fq1-hCK4.js +0 -100
- phoenix/trace/langchain/__init__.py +0 -3
- phoenix/trace/langchain/instrumentor.py +0 -35
- phoenix/trace/llama_index/__init__.py +0 -3
- phoenix/trace/llama_index/callback.py +0 -103
- phoenix/trace/openai/__init__.py +0 -3
- phoenix/trace/openai/instrumentor.py +0 -31
- {arize_phoenix-4.35.2.dist-info → arize_phoenix-5.0.0.dist-info}/WHEEL +0 -0
- {arize_phoenix-4.35.2.dist-info → arize_phoenix-5.0.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-4.35.2.dist-info → arize_phoenix-5.0.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
from typing import
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
from typing import Optional
|
|
3
3
|
|
|
4
|
-
import jwt
|
|
5
4
|
import strawberry
|
|
6
|
-
from sqlalchemy import
|
|
5
|
+
from sqlalchemy import select
|
|
7
6
|
from strawberry import UNSET
|
|
8
7
|
from strawberry.relay import GlobalID
|
|
9
8
|
from strawberry.types import Info
|
|
10
9
|
|
|
11
|
-
from phoenix.db import models
|
|
10
|
+
from phoenix.db import enums, models
|
|
11
|
+
from phoenix.server.api.auth import IsAdmin, IsNotReadOnly
|
|
12
12
|
from phoenix.server.api.context import Context
|
|
13
|
-
from phoenix.server.api.exceptions import
|
|
14
|
-
from phoenix.server.api.mutations.auth import HasSecret, IsAuthenticated
|
|
13
|
+
from phoenix.server.api.exceptions import Unauthorized
|
|
15
14
|
from phoenix.server.api.queries import Query
|
|
16
15
|
from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
17
16
|
from phoenix.server.api.types.SystemApiKey import SystemApiKey
|
|
17
|
+
from phoenix.server.api.types.UserApiKey import UserApiKey
|
|
18
|
+
from phoenix.server.bearer_auth import PhoenixUser
|
|
19
|
+
from phoenix.server.types import ApiKeyAttributes, ApiKeyClaims, ApiKeyId, UserId
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
@strawberry.type
|
|
@@ -31,119 +33,135 @@ class CreateApiKeyInput:
|
|
|
31
33
|
expires_at: Optional[datetime] = UNSET
|
|
32
34
|
|
|
33
35
|
|
|
36
|
+
@strawberry.type
|
|
37
|
+
class CreateUserApiKeyMutationPayload:
|
|
38
|
+
jwt: str
|
|
39
|
+
api_key: UserApiKey
|
|
40
|
+
query: Query
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@strawberry.input
|
|
44
|
+
class CreateUserApiKeyInput:
|
|
45
|
+
name: str
|
|
46
|
+
description: Optional[str] = UNSET
|
|
47
|
+
expires_at: Optional[datetime] = UNSET
|
|
48
|
+
|
|
49
|
+
|
|
34
50
|
@strawberry.input
|
|
35
51
|
class DeleteApiKeyInput:
|
|
36
52
|
id: GlobalID
|
|
37
53
|
|
|
38
54
|
|
|
39
55
|
@strawberry.type
|
|
40
|
-
class
|
|
41
|
-
|
|
56
|
+
class DeleteApiKeyMutationPayload:
|
|
57
|
+
apiKeyId: GlobalID
|
|
42
58
|
query: Query
|
|
43
59
|
|
|
44
60
|
|
|
45
61
|
@strawberry.type
|
|
46
62
|
class ApiKeyMutationMixin:
|
|
47
|
-
@strawberry.mutation(permission_classes=[
|
|
63
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly, IsAdmin]) # type: ignore
|
|
48
64
|
async def create_system_api_key(
|
|
49
65
|
self, info: Info[Context, None], input: CreateApiKeyInput
|
|
50
66
|
) -> CreateSystemApiKeyMutationPayload:
|
|
51
|
-
|
|
67
|
+
assert (token_store := info.context.token_store) is not None
|
|
68
|
+
user_role = enums.UserRole.SYSTEM
|
|
52
69
|
async with info.context.db() as session:
|
|
53
70
|
# Get the system user - note this could be pushed into a dataloader
|
|
54
71
|
system_user = await session.scalar(
|
|
55
72
|
select(models.User)
|
|
56
73
|
.join(models.UserRole) # Join User with UserRole
|
|
57
|
-
.where(models.UserRole.name ==
|
|
74
|
+
.where(models.UserRole.name == user_role.value) # Filter where role is SYSTEM
|
|
75
|
+
.order_by(models.User.id)
|
|
58
76
|
.limit(1)
|
|
59
77
|
)
|
|
60
78
|
if system_user is None:
|
|
61
79
|
raise ValueError("System user not found")
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
)
|
|
73
|
-
api_key = await session.scalar(insert_stmt)
|
|
74
|
-
assert api_key is not None
|
|
75
|
-
|
|
76
|
-
encoded_jwt = create_jwt(
|
|
77
|
-
secret=info.context.get_secret(),
|
|
78
|
-
name=api_key.name,
|
|
79
|
-
id=api_key.id,
|
|
80
|
-
description=api_key.description,
|
|
81
|
-
iat=api_key.created_at,
|
|
82
|
-
exp=api_key.expires_at,
|
|
80
|
+
issued_at = datetime.now(timezone.utc)
|
|
81
|
+
claims = ApiKeyClaims(
|
|
82
|
+
subject=UserId(system_user.id),
|
|
83
|
+
issued_at=issued_at,
|
|
84
|
+
expiration_time=input.expires_at or None,
|
|
85
|
+
attributes=ApiKeyAttributes(
|
|
86
|
+
user_role=user_role,
|
|
87
|
+
name=input.name,
|
|
88
|
+
description=input.description,
|
|
89
|
+
),
|
|
83
90
|
)
|
|
91
|
+
token, token_id = await token_store.create_api_key(claims)
|
|
84
92
|
return CreateSystemApiKeyMutationPayload(
|
|
85
|
-
jwt=
|
|
93
|
+
jwt=token,
|
|
86
94
|
api_key=SystemApiKey(
|
|
87
|
-
id_attr=
|
|
88
|
-
name=
|
|
89
|
-
description=
|
|
90
|
-
created_at=
|
|
91
|
-
expires_at=
|
|
95
|
+
id_attr=int(token_id),
|
|
96
|
+
name=input.name,
|
|
97
|
+
description=input.description or None,
|
|
98
|
+
created_at=issued_at,
|
|
99
|
+
expires_at=input.expires_at or None,
|
|
92
100
|
),
|
|
93
101
|
query=Query(),
|
|
94
102
|
)
|
|
95
103
|
|
|
96
|
-
@strawberry.mutation(permission_classes=[
|
|
104
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
105
|
+
async def create_user_api_key(
|
|
106
|
+
self, info: Info[Context, None], input: CreateUserApiKeyInput
|
|
107
|
+
) -> CreateUserApiKeyMutationPayload:
|
|
108
|
+
assert (token_store := info.context.token_store) is not None
|
|
109
|
+
try:
|
|
110
|
+
user = info.context.request.user # type: ignore
|
|
111
|
+
assert isinstance(user, PhoenixUser)
|
|
112
|
+
except AttributeError:
|
|
113
|
+
raise ValueError("User not found")
|
|
114
|
+
issued_at = datetime.now(timezone.utc)
|
|
115
|
+
claims = ApiKeyClaims(
|
|
116
|
+
subject=user.identity,
|
|
117
|
+
issued_at=issued_at,
|
|
118
|
+
expiration_time=input.expires_at or None,
|
|
119
|
+
attributes=ApiKeyAttributes(
|
|
120
|
+
user_role=enums.UserRole.MEMBER,
|
|
121
|
+
name=input.name,
|
|
122
|
+
description=input.description,
|
|
123
|
+
),
|
|
124
|
+
)
|
|
125
|
+
token, token_id = await token_store.create_api_key(claims)
|
|
126
|
+
return CreateUserApiKeyMutationPayload(
|
|
127
|
+
jwt=token,
|
|
128
|
+
api_key=UserApiKey(
|
|
129
|
+
id_attr=int(token_id),
|
|
130
|
+
name=input.name,
|
|
131
|
+
description=input.description or None,
|
|
132
|
+
created_at=issued_at,
|
|
133
|
+
expires_at=input.expires_at or None,
|
|
134
|
+
user_id=int(user.identity),
|
|
135
|
+
),
|
|
136
|
+
query=Query(),
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly, IsAdmin]) # type: ignore
|
|
97
140
|
async def delete_system_api_key(
|
|
98
141
|
self, info: Info[Context, None], input: DeleteApiKeyInput
|
|
99
|
-
) ->
|
|
142
|
+
) -> DeleteApiKeyMutationPayload:
|
|
143
|
+
assert (token_store := info.context.token_store) is not None
|
|
100
144
|
api_key_id = from_global_id_with_expected_type(
|
|
101
145
|
input.id, expected_type_name=SystemApiKey.__name__
|
|
102
146
|
)
|
|
147
|
+
await token_store.revoke(ApiKeyId(api_key_id))
|
|
148
|
+
return DeleteApiKeyMutationPayload(apiKeyId=input.id, query=Query())
|
|
149
|
+
|
|
150
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
151
|
+
async def delete_user_api_key(
|
|
152
|
+
self, info: Info[Context, None], input: DeleteApiKeyInput
|
|
153
|
+
) -> DeleteApiKeyMutationPayload:
|
|
154
|
+
assert (token_store := info.context.token_store) is not None
|
|
155
|
+
api_key_id = from_global_id_with_expected_type(
|
|
156
|
+
input.id, expected_type_name=UserApiKey.__name__
|
|
157
|
+
)
|
|
103
158
|
async with info.context.db() as session:
|
|
104
|
-
api_key = await session.
|
|
159
|
+
api_key = await session.scalar(
|
|
160
|
+
select(models.ApiKey).where(models.ApiKey.id == api_key_id)
|
|
161
|
+
)
|
|
105
162
|
if api_key is None:
|
|
106
|
-
raise
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def create_jwt(
|
|
114
|
-
*,
|
|
115
|
-
secret: str,
|
|
116
|
-
algorithm: str = "HS256",
|
|
117
|
-
name: str,
|
|
118
|
-
description: Optional[str],
|
|
119
|
-
iat: datetime,
|
|
120
|
-
exp: Optional[datetime],
|
|
121
|
-
id: int,
|
|
122
|
-
) -> str:
|
|
123
|
-
"""Create a signed JSON Web Token for authentication
|
|
124
|
-
|
|
125
|
-
Args:
|
|
126
|
-
secret (str): the secret to sign with
|
|
127
|
-
name (str): name of the key / token
|
|
128
|
-
description (Optional[str]): description of the token
|
|
129
|
-
iat (datetime): the issued at time
|
|
130
|
-
exp (Optional[datetime]): the expiry, if set
|
|
131
|
-
id (int): the id of the key
|
|
132
|
-
algorithm (str, optional): the algorithm to use. Defaults to "HS256".
|
|
133
|
-
|
|
134
|
-
Returns:
|
|
135
|
-
str: The encoded JWT
|
|
136
|
-
"""
|
|
137
|
-
payload: Dict[str, Any] = {
|
|
138
|
-
"name": name,
|
|
139
|
-
"description": description,
|
|
140
|
-
"iat": iat.utcnow(),
|
|
141
|
-
"id": id,
|
|
142
|
-
}
|
|
143
|
-
if exp is not None:
|
|
144
|
-
payload["exp"] = exp.utcnow()
|
|
145
|
-
|
|
146
|
-
# Encode the payload to create the JWT
|
|
147
|
-
token = jwt.encode(payload, secret, algorithm=algorithm)
|
|
148
|
-
|
|
149
|
-
return token
|
|
163
|
+
raise ValueError(f"API key with id {input.id} not found")
|
|
164
|
+
if int((user := info.context.user).identity) != api_key.user_id and not user.is_admin:
|
|
165
|
+
raise Unauthorized("User not authorized to delete")
|
|
166
|
+
await token_store.revoke(ApiKeyId(api_key_id))
|
|
167
|
+
return DeleteApiKeyMutationPayload(apiKeyId=input.id, query=Query())
|
|
@@ -12,6 +12,7 @@ from strawberry.types import Info
|
|
|
12
12
|
|
|
13
13
|
from phoenix.db import models
|
|
14
14
|
from phoenix.db.helpers import get_eval_trace_ids_for_datasets, get_project_names_for_datasets
|
|
15
|
+
from phoenix.server.api.auth import IsNotReadOnly
|
|
15
16
|
from phoenix.server.api.context import Context
|
|
16
17
|
from phoenix.server.api.exceptions import BadRequest, NotFound
|
|
17
18
|
from phoenix.server.api.helpers.dataset_helpers import (
|
|
@@ -28,7 +29,6 @@ from phoenix.server.api.input_types.PatchDatasetExamplesInput import (
|
|
|
28
29
|
PatchDatasetExamplesInput,
|
|
29
30
|
)
|
|
30
31
|
from phoenix.server.api.input_types.PatchDatasetInput import PatchDatasetInput
|
|
31
|
-
from phoenix.server.api.mutations.auth import IsAuthenticated
|
|
32
32
|
from phoenix.server.api.types.Dataset import Dataset, to_gql_dataset
|
|
33
33
|
from phoenix.server.api.types.DatasetExample import DatasetExample
|
|
34
34
|
from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
@@ -44,7 +44,7 @@ class DatasetMutationPayload:
|
|
|
44
44
|
|
|
45
45
|
@strawberry.type
|
|
46
46
|
class DatasetMutationMixin:
|
|
47
|
-
@strawberry.mutation(permission_classes=[
|
|
47
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
48
48
|
async def create_dataset(
|
|
49
49
|
self,
|
|
50
50
|
info: Info[Context, None],
|
|
@@ -67,7 +67,7 @@ class DatasetMutationMixin:
|
|
|
67
67
|
info.context.event_queue.put(DatasetInsertEvent((dataset.id,)))
|
|
68
68
|
return DatasetMutationPayload(dataset=to_gql_dataset(dataset))
|
|
69
69
|
|
|
70
|
-
@strawberry.mutation(permission_classes=[
|
|
70
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
71
71
|
async def patch_dataset(
|
|
72
72
|
self,
|
|
73
73
|
info: Info[Context, None],
|
|
@@ -96,7 +96,7 @@ class DatasetMutationMixin:
|
|
|
96
96
|
info.context.event_queue.put(DatasetInsertEvent((dataset.id,)))
|
|
97
97
|
return DatasetMutationPayload(dataset=to_gql_dataset(dataset))
|
|
98
98
|
|
|
99
|
-
@strawberry.mutation(permission_classes=[
|
|
99
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
100
100
|
async def add_spans_to_dataset(
|
|
101
101
|
self,
|
|
102
102
|
info: Info[Context, None],
|
|
@@ -225,7 +225,7 @@ class DatasetMutationMixin:
|
|
|
225
225
|
info.context.event_queue.put(DatasetInsertEvent((dataset.id,)))
|
|
226
226
|
return DatasetMutationPayload(dataset=to_gql_dataset(dataset))
|
|
227
227
|
|
|
228
|
-
@strawberry.mutation(permission_classes=[
|
|
228
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
229
229
|
async def add_examples_to_dataset(
|
|
230
230
|
self, info: Info[Context, None], input: AddExamplesToDatasetInput
|
|
231
231
|
) -> DatasetMutationPayload:
|
|
@@ -351,7 +351,7 @@ class DatasetMutationMixin:
|
|
|
351
351
|
info.context.event_queue.put(DatasetInsertEvent((dataset.id,)))
|
|
352
352
|
return DatasetMutationPayload(dataset=to_gql_dataset(dataset))
|
|
353
353
|
|
|
354
|
-
@strawberry.mutation(permission_classes=[
|
|
354
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
355
355
|
async def delete_dataset(
|
|
356
356
|
self,
|
|
357
357
|
info: Info[Context, None],
|
|
@@ -382,7 +382,7 @@ class DatasetMutationMixin:
|
|
|
382
382
|
info.context.event_queue.put(DatasetDeleteEvent((dataset.id,)))
|
|
383
383
|
return DatasetMutationPayload(dataset=to_gql_dataset(dataset))
|
|
384
384
|
|
|
385
|
-
@strawberry.mutation(permission_classes=[
|
|
385
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
386
386
|
async def patch_dataset_examples(
|
|
387
387
|
self,
|
|
388
388
|
info: Info[Context, None],
|
|
@@ -474,7 +474,7 @@ class DatasetMutationMixin:
|
|
|
474
474
|
info.context.event_queue.put(DatasetInsertEvent((dataset.id,)))
|
|
475
475
|
return DatasetMutationPayload(dataset=to_gql_dataset(dataset))
|
|
476
476
|
|
|
477
|
-
@strawberry.mutation(permission_classes=[
|
|
477
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
478
478
|
async def delete_dataset_examples(
|
|
479
479
|
self, info: Info[Context, None], input: DeleteDatasetExamplesInput
|
|
480
480
|
) -> DatasetMutationPayload:
|
|
@@ -8,10 +8,10 @@ from strawberry.types import Info
|
|
|
8
8
|
|
|
9
9
|
from phoenix.db import models
|
|
10
10
|
from phoenix.db.helpers import get_eval_trace_ids_for_experiments, get_project_names_for_experiments
|
|
11
|
+
from phoenix.server.api.auth import IsNotReadOnly
|
|
11
12
|
from phoenix.server.api.context import Context
|
|
12
13
|
from phoenix.server.api.exceptions import CustomGraphQLError
|
|
13
14
|
from phoenix.server.api.input_types.DeleteExperimentsInput import DeleteExperimentsInput
|
|
14
|
-
from phoenix.server.api.mutations.auth import IsAuthenticated
|
|
15
15
|
from phoenix.server.api.types.Experiment import Experiment, to_gql_experiment
|
|
16
16
|
from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
17
17
|
from phoenix.server.api.utils import delete_projects, delete_traces
|
|
@@ -25,7 +25,7 @@ class ExperimentMutationPayload:
|
|
|
25
25
|
|
|
26
26
|
@strawberry.type
|
|
27
27
|
class ExperimentMutationMixin:
|
|
28
|
-
@strawberry.mutation(permission_classes=[
|
|
28
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
29
29
|
async def delete_experiments(
|
|
30
30
|
self,
|
|
31
31
|
info: Info[Context, None],
|
|
@@ -8,9 +8,9 @@ from strawberry import ID, UNSET
|
|
|
8
8
|
from strawberry.types import Info
|
|
9
9
|
|
|
10
10
|
import phoenix.core.model_schema as ms
|
|
11
|
+
from phoenix.server.api.auth import IsNotReadOnly
|
|
11
12
|
from phoenix.server.api.context import Context
|
|
12
13
|
from phoenix.server.api.input_types.ClusterInput import ClusterInput
|
|
13
|
-
from phoenix.server.api.mutations.auth import IsAuthenticated
|
|
14
14
|
from phoenix.server.api.types.Event import parse_event_ids_by_inferences_role, unpack_event_id
|
|
15
15
|
from phoenix.server.api.types.ExportedFile import ExportedFile
|
|
16
16
|
from phoenix.server.api.types.InferencesRole import AncillaryInferencesRole, InferencesRole
|
|
@@ -19,7 +19,7 @@ from phoenix.server.api.types.InferencesRole import AncillaryInferencesRole, Inf
|
|
|
19
19
|
@strawberry.type
|
|
20
20
|
class ExportEventsMutationMixin:
|
|
21
21
|
@strawberry.mutation(
|
|
22
|
-
permission_classes=[
|
|
22
|
+
permission_classes=[IsNotReadOnly],
|
|
23
23
|
description=(
|
|
24
24
|
"Given a list of event ids, export the corresponding data subset in Parquet format."
|
|
25
25
|
" File name is optional, but if specified, should be without file extension. By default"
|
|
@@ -51,7 +51,7 @@ class ExportEventsMutationMixin:
|
|
|
51
51
|
return ExportedFile(file_name=file_name)
|
|
52
52
|
|
|
53
53
|
@strawberry.mutation(
|
|
54
|
-
permission_classes=[
|
|
54
|
+
permission_classes=[IsNotReadOnly],
|
|
55
55
|
description=(
|
|
56
56
|
"Given a list of clusters, export the corresponding data subset in Parquet format."
|
|
57
57
|
" File name is optional, but if specified, should be without file extension. By default"
|
|
@@ -6,9 +6,9 @@ from strawberry.types import Info
|
|
|
6
6
|
|
|
7
7
|
from phoenix.config import DEFAULT_PROJECT_NAME
|
|
8
8
|
from phoenix.db import models
|
|
9
|
+
from phoenix.server.api.auth import IsNotReadOnly
|
|
9
10
|
from phoenix.server.api.context import Context
|
|
10
11
|
from phoenix.server.api.input_types.ClearProjectInput import ClearProjectInput
|
|
11
|
-
from phoenix.server.api.mutations.auth import IsAuthenticated
|
|
12
12
|
from phoenix.server.api.queries import Query
|
|
13
13
|
from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
14
14
|
from phoenix.server.dml_event import ProjectDeleteEvent, SpanDeleteEvent
|
|
@@ -16,7 +16,7 @@ from phoenix.server.dml_event import ProjectDeleteEvent, SpanDeleteEvent
|
|
|
16
16
|
|
|
17
17
|
@strawberry.type
|
|
18
18
|
class ProjectMutationMixin:
|
|
19
|
-
@strawberry.mutation(permission_classes=[
|
|
19
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
20
20
|
async def delete_project(self, info: Info[Context, None], id: GlobalID) -> Query:
|
|
21
21
|
project_id = from_global_id_with_expected_type(global_id=id, expected_type_name="Project")
|
|
22
22
|
async with info.context.db() as session:
|
|
@@ -33,7 +33,7 @@ class ProjectMutationMixin:
|
|
|
33
33
|
info.context.event_queue.put(ProjectDeleteEvent((project_id,)))
|
|
34
34
|
return Query()
|
|
35
35
|
|
|
36
|
-
@strawberry.mutation(permission_classes=[
|
|
36
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
37
37
|
async def clear_project(self, info: Info[Context, None], input: ClearProjectInput) -> Query:
|
|
38
38
|
project_id = from_global_id_with_expected_type(
|
|
39
39
|
global_id=input.id, expected_type_name="Project"
|
|
@@ -6,11 +6,11 @@ from strawberry import UNSET
|
|
|
6
6
|
from strawberry.types import Info
|
|
7
7
|
|
|
8
8
|
from phoenix.db import models
|
|
9
|
+
from phoenix.server.api.auth import IsNotReadOnly
|
|
9
10
|
from phoenix.server.api.context import Context
|
|
10
11
|
from phoenix.server.api.input_types.CreateSpanAnnotationInput import CreateSpanAnnotationInput
|
|
11
12
|
from phoenix.server.api.input_types.DeleteAnnotationsInput import DeleteAnnotationsInput
|
|
12
13
|
from phoenix.server.api.input_types.PatchAnnotationInput import PatchAnnotationInput
|
|
13
|
-
from phoenix.server.api.mutations.auth import IsAuthenticated
|
|
14
14
|
from phoenix.server.api.queries import Query
|
|
15
15
|
from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
16
16
|
from phoenix.server.api.types.SpanAnnotation import SpanAnnotation, to_gql_span_annotation
|
|
@@ -25,7 +25,7 @@ class SpanAnnotationMutationPayload:
|
|
|
25
25
|
|
|
26
26
|
@strawberry.type
|
|
27
27
|
class SpanAnnotationMutationMixin:
|
|
28
|
-
@strawberry.mutation(permission_classes=[
|
|
28
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
29
29
|
async def create_span_annotations(
|
|
30
30
|
self, info: Info[Context, None], input: List[CreateSpanAnnotationInput]
|
|
31
31
|
) -> SpanAnnotationMutationPayload:
|
|
@@ -59,7 +59,7 @@ class SpanAnnotationMutationMixin:
|
|
|
59
59
|
query=Query(),
|
|
60
60
|
)
|
|
61
61
|
|
|
62
|
-
@strawberry.mutation(permission_classes=[
|
|
62
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
63
63
|
async def patch_span_annotations(
|
|
64
64
|
self, info: Info[Context, None], input: List[PatchAnnotationInput]
|
|
65
65
|
) -> SpanAnnotationMutationPayload:
|
|
@@ -99,7 +99,7 @@ class SpanAnnotationMutationMixin:
|
|
|
99
99
|
info.context.event_queue.put(SpanAnnotationInsertEvent((span_annotation.id,)))
|
|
100
100
|
return SpanAnnotationMutationPayload(span_annotations=patched_annotations, query=Query())
|
|
101
101
|
|
|
102
|
-
@strawberry.mutation(permission_classes=[
|
|
102
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
103
103
|
async def delete_span_annotations(
|
|
104
104
|
self, info: Info[Context, None], input: DeleteAnnotationsInput
|
|
105
105
|
) -> SpanAnnotationMutationPayload:
|
|
@@ -6,11 +6,11 @@ from strawberry import UNSET
|
|
|
6
6
|
from strawberry.types import Info
|
|
7
7
|
|
|
8
8
|
from phoenix.db import models
|
|
9
|
+
from phoenix.server.api.auth import IsNotReadOnly
|
|
9
10
|
from phoenix.server.api.context import Context
|
|
10
11
|
from phoenix.server.api.input_types.CreateTraceAnnotationInput import CreateTraceAnnotationInput
|
|
11
12
|
from phoenix.server.api.input_types.DeleteAnnotationsInput import DeleteAnnotationsInput
|
|
12
13
|
from phoenix.server.api.input_types.PatchAnnotationInput import PatchAnnotationInput
|
|
13
|
-
from phoenix.server.api.mutations.auth import IsAuthenticated
|
|
14
14
|
from phoenix.server.api.queries import Query
|
|
15
15
|
from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
16
16
|
from phoenix.server.api.types.TraceAnnotation import TraceAnnotation, to_gql_trace_annotation
|
|
@@ -25,7 +25,7 @@ class TraceAnnotationMutationPayload:
|
|
|
25
25
|
|
|
26
26
|
@strawberry.type
|
|
27
27
|
class TraceAnnotationMutationMixin:
|
|
28
|
-
@strawberry.mutation(permission_classes=[
|
|
28
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
29
29
|
async def create_trace_annotations(
|
|
30
30
|
self, info: Info[Context, None], input: List[CreateTraceAnnotationInput]
|
|
31
31
|
) -> TraceAnnotationMutationPayload:
|
|
@@ -59,7 +59,7 @@ class TraceAnnotationMutationMixin:
|
|
|
59
59
|
query=Query(),
|
|
60
60
|
)
|
|
61
61
|
|
|
62
|
-
@strawberry.mutation(permission_classes=[
|
|
62
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
63
63
|
async def patch_trace_annotations(
|
|
64
64
|
self, info: Info[Context, None], input: List[PatchAnnotationInput]
|
|
65
65
|
) -> TraceAnnotationMutationPayload:
|
|
@@ -98,7 +98,7 @@ class TraceAnnotationMutationMixin:
|
|
|
98
98
|
info.context.event_queue.put(TraceAnnotationInsertEvent((trace_annotation.id,)))
|
|
99
99
|
return TraceAnnotationMutationPayload(trace_annotations=patched_annotations, query=Query())
|
|
100
100
|
|
|
101
|
-
@strawberry.mutation(permission_classes=[
|
|
101
|
+
@strawberry.mutation(permission_classes=[IsNotReadOnly]) # type: ignore
|
|
102
102
|
async def delete_trace_annotations(
|
|
103
103
|
self, info: Info[Context, None], input: DeleteAnnotationsInput
|
|
104
104
|
) -> TraceAnnotationMutationPayload:
|