arize-phoenix 8.8.0__py3-none-any.whl → 8.10.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 (30) hide show
  1. {arize_phoenix-8.8.0.dist-info → arize_phoenix-8.10.0.dist-info}/METADATA +4 -4
  2. {arize_phoenix-8.8.0.dist-info → arize_phoenix-8.10.0.dist-info}/RECORD +30 -29
  3. phoenix/config.py +11 -0
  4. phoenix/experiments/types.py +2 -0
  5. phoenix/server/api/helpers/playground_clients.py +30 -2
  6. phoenix/server/api/helpers/prompts/models.py +23 -2
  7. phoenix/server/api/input_types/InvocationParameters.py +1 -0
  8. phoenix/server/api/mutations/__init__.py +3 -1
  9. phoenix/server/api/mutations/prompt_label_mutations.py +6 -5
  10. phoenix/server/api/mutations/prompt_mutations.py +6 -5
  11. phoenix/server/api/mutations/prompt_version_tag_mutations.py +3 -2
  12. phoenix/server/api/mutations/trace_mutations.py +74 -0
  13. phoenix/server/api/queries.py +14 -1
  14. phoenix/server/api/routers/v1/experiments.py +103 -2
  15. phoenix/server/api/routers/v1/prompts.py +14 -2
  16. phoenix/server/app.py +1 -1
  17. phoenix/server/static/.vite/manifest.json +44 -44
  18. phoenix/server/static/assets/{components-Cvwn-4Sk.js → components-CVzKofML.js} +245 -238
  19. phoenix/server/static/assets/{index-Cxmc6_pQ.js → index-Ctff7oin.js} +1 -1
  20. phoenix/server/static/assets/{pages-DLMdDkgQ.js → pages-CVFLHgre.js} +349 -340
  21. phoenix/server/static/assets/{vendor-yn6w6Ozi.js → vendor-VJCVsFqd.js} +161 -161
  22. phoenix/server/static/assets/{vendor-arizeai-DoGO67dU.js → vendor-arizeai-BiZagY4a.js} +22 -22
  23. phoenix/server/static/assets/{vendor-codemirror-BLdSYxpm.js → vendor-codemirror-0mUqu36F.js} +11 -11
  24. phoenix/server/static/assets/{vendor-recharts-CjOpOw1c.js → vendor-recharts-CfKQSOmq.js} +1 -1
  25. phoenix/server/static/assets/{vendor-shiki-BwTCxCQY.js → vendor-shiki-BsgMOuir.js} +1 -1
  26. phoenix/version.py +1 -1
  27. {arize_phoenix-8.8.0.dist-info → arize_phoenix-8.10.0.dist-info}/WHEEL +0 -0
  28. {arize_phoenix-8.8.0.dist-info → arize_phoenix-8.10.0.dist-info}/entry_points.txt +0 -0
  29. {arize_phoenix-8.8.0.dist-info → arize_phoenix-8.10.0.dist-info}/licenses/IP_NOTICE +0 -0
  30. {arize_phoenix-8.8.0.dist-info → arize_phoenix-8.10.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,11 +1,13 @@
1
+ import json
1
2
  from datetime import datetime
2
3
  from random import getrandbits
3
4
  from typing import Any, Optional
4
5
 
5
- from fastapi import APIRouter, HTTPException, Path
6
+ from fastapi import APIRouter, HTTPException, Path, Response
6
7
  from pydantic import Field
7
- from sqlalchemy import select
8
+ from sqlalchemy import and_, func, select
8
9
  from starlette.requests import Request
10
+ from starlette.responses import PlainTextResponse
9
11
  from starlette.status import HTTP_404_NOT_FOUND
10
12
  from strawberry.relay import GlobalID
11
13
 
@@ -306,3 +308,102 @@ async def list_experiments(
306
308
  ]
307
309
 
308
310
  return ListExperimentsResponseBody(data=data)
311
+
312
+
313
+ @router.get(
314
+ "/experiments/{experiment_id}/json",
315
+ operation_id="getExperimentJSON",
316
+ summary="Download experiment runs as a JSON file",
317
+ response_class=PlainTextResponse,
318
+ responses=add_errors_to_responses(
319
+ [
320
+ {"status_code": HTTP_404_NOT_FOUND, "description": "Experiment not found"},
321
+ ]
322
+ ),
323
+ )
324
+ async def get_experiment_jsonl(
325
+ request: Request,
326
+ response: Response,
327
+ experiment_id: str = Path(..., title="Experiment ID"),
328
+ ) -> str:
329
+ experiment_globalid = GlobalID.from_id(experiment_id)
330
+ try:
331
+ experiment_rowid = from_global_id_with_expected_type(experiment_globalid, "Experiment")
332
+ except ValueError:
333
+ raise HTTPException(
334
+ detail=f"Experiment with ID {experiment_globalid} does not exist",
335
+ status_code=HTTP_404_NOT_FOUND,
336
+ )
337
+
338
+ async with request.app.state.db() as session:
339
+ experiment = await session.get(models.Experiment, experiment_rowid)
340
+ if not experiment:
341
+ raise HTTPException(
342
+ detail=f"Experiment with ID {experiment_globalid} does not exist",
343
+ status_code=HTTP_404_NOT_FOUND,
344
+ )
345
+ revision_ids = (
346
+ select(func.max(models.DatasetExampleRevision.id))
347
+ .join(
348
+ models.DatasetExample,
349
+ models.DatasetExample.id == models.DatasetExampleRevision.dataset_example_id,
350
+ )
351
+ .where(
352
+ and_(
353
+ models.DatasetExampleRevision.dataset_version_id
354
+ <= experiment.dataset_version_id,
355
+ models.DatasetExample.dataset_id == experiment.dataset_id,
356
+ )
357
+ )
358
+ .group_by(models.DatasetExampleRevision.dataset_example_id)
359
+ .scalar_subquery()
360
+ )
361
+ runs_and_revisions = (
362
+ await session.execute(
363
+ select(models.ExperimentRun, models.DatasetExampleRevision)
364
+ .join(
365
+ models.DatasetExample,
366
+ models.DatasetExample.id == models.ExperimentRun.dataset_example_id,
367
+ )
368
+ .join(
369
+ models.DatasetExampleRevision,
370
+ and_(
371
+ models.DatasetExample.id
372
+ == models.DatasetExampleRevision.dataset_example_id,
373
+ models.DatasetExampleRevision.id.in_(revision_ids),
374
+ models.DatasetExampleRevision.revision_kind != "DELETE",
375
+ ),
376
+ )
377
+ .where(models.ExperimentRun.experiment_id == experiment_rowid)
378
+ .order_by(
379
+ models.ExperimentRun.dataset_example_id, models.ExperimentRun.repetition_number
380
+ )
381
+ )
382
+ ).all()
383
+ if not runs_and_revisions:
384
+ raise HTTPException(
385
+ detail=f"Experiment with ID {experiment_globalid} has no runs",
386
+ status_code=HTTP_404_NOT_FOUND,
387
+ )
388
+ records = []
389
+ for run, revision in runs_and_revisions:
390
+ record = {
391
+ "example_id": str(
392
+ GlobalID(models.DatasetExample.__name__, str(run.dataset_example_id))
393
+ ),
394
+ "repetition_number": run.repetition_number,
395
+ "input": revision.input,
396
+ "reference_output": revision.output,
397
+ "output": run.output,
398
+ "error": run.error,
399
+ "latency_ms": run.latency_ms,
400
+ "start_time": run.start_time.isoformat(),
401
+ "end_time": run.end_time.isoformat(),
402
+ "trace_id": run.trace_id,
403
+ "prompt_token_count": run.prompt_token_count,
404
+ "completion_token_count": run.completion_token_count,
405
+ }
406
+ records.append(record)
407
+
408
+ response.headers["content-disposition"] = f'attachment; filename="{experiment.name}.json"'
409
+ return json.dumps(records, ensure_ascii=False, indent=2)
@@ -2,13 +2,13 @@ import logging
2
2
  from typing import Any, Optional, Union
3
3
 
4
4
  from fastapi import APIRouter, HTTPException, Path, Query
5
- from pydantic import ValidationError
5
+ from pydantic import ValidationError, model_validator
6
6
  from sqlalchemy import select
7
7
  from sqlalchemy.sql import Select
8
8
  from starlette.requests import Request
9
9
  from starlette.status import HTTP_404_NOT_FOUND, HTTP_422_UNPROCESSABLE_ENTITY
10
10
  from strawberry.relay import GlobalID
11
- from typing_extensions import TypeAlias, assert_never
11
+ from typing_extensions import Self, TypeAlias, assert_never
12
12
 
13
13
  from phoenix.db import models
14
14
  from phoenix.db.types.identifier import Identifier
@@ -52,6 +52,18 @@ class PromptVersionData(V1RoutesBaseModel):
52
52
  tools: Optional[PromptTools] = None
53
53
  response_format: Optional[PromptResponseFormat] = None
54
54
 
55
+ @model_validator(mode="after")
56
+ def check_template_type_match(self) -> Self:
57
+ if self.template_type is PromptTemplateType.CHAT:
58
+ if self.template.type == "chat":
59
+ return self
60
+ elif self.template_type is PromptTemplateType.STRING:
61
+ if self.template.type == "string":
62
+ return self
63
+ else:
64
+ assert_never(self.template_type)
65
+ raise ValueError("Template type does not match template")
66
+
55
67
 
56
68
  class PromptVersion(PromptVersionData):
57
69
  id: str
phoenix/server/app.py CHANGED
@@ -549,7 +549,7 @@ def create_graphql_router(
549
549
  read_only: bool = False,
550
550
  secret: Optional[str] = None,
551
551
  token_store: Optional[TokenStore] = None,
552
- ) -> GraphQLRouter: # type: ignore[type-arg]
552
+ ) -> GraphQLRouter[Context, None]:
553
553
  """Creates the GraphQL router.
554
554
 
555
555
  Args:
@@ -1,87 +1,87 @@
1
1
  {
2
- "_components-Cvwn-4Sk.js": {
3
- "file": "assets/components-Cvwn-4Sk.js",
2
+ "_components-CVzKofML.js": {
3
+ "file": "assets/components-CVzKofML.js",
4
4
  "name": "components",
5
5
  "imports": [
6
- "_vendor-yn6w6Ozi.js",
7
- "_pages-DLMdDkgQ.js",
8
- "_vendor-arizeai-DoGO67dU.js",
9
- "_vendor-codemirror-BLdSYxpm.js",
6
+ "_vendor-VJCVsFqd.js",
7
+ "_pages-CVFLHgre.js",
8
+ "_vendor-arizeai-BiZagY4a.js",
9
+ "_vendor-codemirror-0mUqu36F.js",
10
10
  "_vendor-three-C-AGeJYv.js"
11
11
  ]
12
12
  },
13
- "_pages-DLMdDkgQ.js": {
14
- "file": "assets/pages-DLMdDkgQ.js",
13
+ "_pages-CVFLHgre.js": {
14
+ "file": "assets/pages-CVFLHgre.js",
15
15
  "name": "pages",
16
16
  "imports": [
17
- "_vendor-yn6w6Ozi.js",
18
- "_vendor-arizeai-DoGO67dU.js",
19
- "_components-Cvwn-4Sk.js",
20
- "_vendor-codemirror-BLdSYxpm.js",
21
- "_vendor-recharts-CjOpOw1c.js"
17
+ "_vendor-VJCVsFqd.js",
18
+ "_vendor-arizeai-BiZagY4a.js",
19
+ "_components-CVzKofML.js",
20
+ "_vendor-codemirror-0mUqu36F.js",
21
+ "_vendor-recharts-CfKQSOmq.js"
22
22
  ]
23
23
  },
24
24
  "_vendor-Cg6lcjUC.css": {
25
25
  "file": "assets/vendor-Cg6lcjUC.css",
26
26
  "src": "_vendor-Cg6lcjUC.css"
27
27
  },
28
- "_vendor-arizeai-DoGO67dU.js": {
29
- "file": "assets/vendor-arizeai-DoGO67dU.js",
28
+ "_vendor-VJCVsFqd.js": {
29
+ "file": "assets/vendor-VJCVsFqd.js",
30
+ "name": "vendor",
31
+ "imports": [
32
+ "_vendor-three-C-AGeJYv.js"
33
+ ],
34
+ "css": [
35
+ "assets/vendor-Cg6lcjUC.css"
36
+ ]
37
+ },
38
+ "_vendor-arizeai-BiZagY4a.js": {
39
+ "file": "assets/vendor-arizeai-BiZagY4a.js",
30
40
  "name": "vendor-arizeai",
31
41
  "imports": [
32
- "_vendor-yn6w6Ozi.js"
42
+ "_vendor-VJCVsFqd.js"
33
43
  ]
34
44
  },
35
- "_vendor-codemirror-BLdSYxpm.js": {
36
- "file": "assets/vendor-codemirror-BLdSYxpm.js",
45
+ "_vendor-codemirror-0mUqu36F.js": {
46
+ "file": "assets/vendor-codemirror-0mUqu36F.js",
37
47
  "name": "vendor-codemirror",
38
48
  "imports": [
39
- "_vendor-yn6w6Ozi.js",
40
- "_vendor-shiki-BwTCxCQY.js"
49
+ "_vendor-VJCVsFqd.js",
50
+ "_vendor-shiki-BsgMOuir.js"
41
51
  ]
42
52
  },
43
- "_vendor-recharts-CjOpOw1c.js": {
44
- "file": "assets/vendor-recharts-CjOpOw1c.js",
53
+ "_vendor-recharts-CfKQSOmq.js": {
54
+ "file": "assets/vendor-recharts-CfKQSOmq.js",
45
55
  "name": "vendor-recharts",
46
56
  "imports": [
47
- "_vendor-yn6w6Ozi.js"
57
+ "_vendor-VJCVsFqd.js"
48
58
  ]
49
59
  },
50
- "_vendor-shiki-BwTCxCQY.js": {
51
- "file": "assets/vendor-shiki-BwTCxCQY.js",
60
+ "_vendor-shiki-BsgMOuir.js": {
61
+ "file": "assets/vendor-shiki-BsgMOuir.js",
52
62
  "name": "vendor-shiki",
53
63
  "imports": [
54
- "_vendor-yn6w6Ozi.js"
64
+ "_vendor-VJCVsFqd.js"
55
65
  ]
56
66
  },
57
67
  "_vendor-three-C-AGeJYv.js": {
58
68
  "file": "assets/vendor-three-C-AGeJYv.js",
59
69
  "name": "vendor-three"
60
70
  },
61
- "_vendor-yn6w6Ozi.js": {
62
- "file": "assets/vendor-yn6w6Ozi.js",
63
- "name": "vendor",
64
- "imports": [
65
- "_vendor-three-C-AGeJYv.js"
66
- ],
67
- "css": [
68
- "assets/vendor-Cg6lcjUC.css"
69
- ]
70
- },
71
71
  "index.tsx": {
72
- "file": "assets/index-Cxmc6_pQ.js",
72
+ "file": "assets/index-Ctff7oin.js",
73
73
  "name": "index",
74
74
  "src": "index.tsx",
75
75
  "isEntry": true,
76
76
  "imports": [
77
- "_vendor-yn6w6Ozi.js",
78
- "_vendor-arizeai-DoGO67dU.js",
79
- "_pages-DLMdDkgQ.js",
80
- "_components-Cvwn-4Sk.js",
77
+ "_vendor-VJCVsFqd.js",
78
+ "_vendor-arizeai-BiZagY4a.js",
79
+ "_pages-CVFLHgre.js",
80
+ "_components-CVzKofML.js",
81
81
  "_vendor-three-C-AGeJYv.js",
82
- "_vendor-codemirror-BLdSYxpm.js",
83
- "_vendor-shiki-BwTCxCQY.js",
84
- "_vendor-recharts-CjOpOw1c.js"
82
+ "_vendor-codemirror-0mUqu36F.js",
83
+ "_vendor-shiki-BsgMOuir.js",
84
+ "_vendor-recharts-CfKQSOmq.js"
85
85
  ]
86
86
  }
87
87
  }