arize-phoenix 11.23.1__py3-none-any.whl → 12.28.1__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.
- {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/METADATA +61 -36
- {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/RECORD +212 -162
- {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/WHEEL +1 -1
- {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/licenses/IP_NOTICE +1 -1
- phoenix/__generated__/__init__.py +0 -0
- phoenix/__generated__/classification_evaluator_configs/__init__.py +20 -0
- phoenix/__generated__/classification_evaluator_configs/_document_relevance_classification_evaluator_config.py +17 -0
- phoenix/__generated__/classification_evaluator_configs/_hallucination_classification_evaluator_config.py +17 -0
- phoenix/__generated__/classification_evaluator_configs/_models.py +18 -0
- phoenix/__generated__/classification_evaluator_configs/_tool_selection_classification_evaluator_config.py +17 -0
- phoenix/__init__.py +2 -1
- phoenix/auth.py +27 -2
- phoenix/config.py +1594 -81
- phoenix/db/README.md +546 -28
- phoenix/db/bulk_inserter.py +119 -116
- phoenix/db/engines.py +140 -33
- phoenix/db/facilitator.py +22 -1
- phoenix/db/helpers.py +818 -65
- phoenix/db/iam_auth.py +64 -0
- phoenix/db/insertion/dataset.py +133 -1
- phoenix/db/insertion/document_annotation.py +9 -6
- phoenix/db/insertion/evaluation.py +2 -3
- phoenix/db/insertion/helpers.py +2 -2
- phoenix/db/insertion/session_annotation.py +176 -0
- phoenix/db/insertion/span_annotation.py +3 -4
- phoenix/db/insertion/trace_annotation.py +3 -4
- phoenix/db/insertion/types.py +41 -18
- phoenix/db/migrations/versions/01a8342c9cdf_add_user_id_on_datasets.py +40 -0
- phoenix/db/migrations/versions/0df286449799_add_session_annotations_table.py +105 -0
- phoenix/db/migrations/versions/272b66ff50f8_drop_single_indices.py +119 -0
- phoenix/db/migrations/versions/58228d933c91_dataset_labels.py +67 -0
- phoenix/db/migrations/versions/699f655af132_experiment_tags.py +57 -0
- phoenix/db/migrations/versions/735d3d93c33e_add_composite_indices.py +41 -0
- phoenix/db/migrations/versions/ab513d89518b_add_user_id_on_dataset_versions.py +40 -0
- phoenix/db/migrations/versions/d0690a79ea51_users_on_experiments.py +40 -0
- phoenix/db/migrations/versions/deb2c81c0bb2_dataset_splits.py +139 -0
- phoenix/db/migrations/versions/e76cbd66ffc3_add_experiments_dataset_examples.py +87 -0
- phoenix/db/models.py +364 -56
- phoenix/db/pg_config.py +10 -0
- phoenix/db/types/trace_retention.py +7 -6
- phoenix/experiments/functions.py +69 -19
- phoenix/inferences/inferences.py +1 -2
- phoenix/server/api/auth.py +9 -0
- phoenix/server/api/auth_messages.py +46 -0
- phoenix/server/api/context.py +60 -0
- phoenix/server/api/dataloaders/__init__.py +36 -0
- phoenix/server/api/dataloaders/annotation_summaries.py +60 -8
- phoenix/server/api/dataloaders/average_experiment_repeated_run_group_latency.py +50 -0
- phoenix/server/api/dataloaders/average_experiment_run_latency.py +17 -24
- phoenix/server/api/dataloaders/cache/two_tier_cache.py +1 -2
- phoenix/server/api/dataloaders/dataset_dataset_splits.py +52 -0
- phoenix/server/api/dataloaders/dataset_example_revisions.py +0 -1
- phoenix/server/api/dataloaders/dataset_example_splits.py +40 -0
- phoenix/server/api/dataloaders/dataset_examples_and_versions_by_experiment_run.py +47 -0
- phoenix/server/api/dataloaders/dataset_labels.py +36 -0
- phoenix/server/api/dataloaders/document_evaluation_summaries.py +2 -2
- phoenix/server/api/dataloaders/document_evaluations.py +6 -9
- phoenix/server/api/dataloaders/experiment_annotation_summaries.py +88 -34
- phoenix/server/api/dataloaders/experiment_dataset_splits.py +43 -0
- phoenix/server/api/dataloaders/experiment_error_rates.py +21 -28
- phoenix/server/api/dataloaders/experiment_repeated_run_group_annotation_summaries.py +77 -0
- phoenix/server/api/dataloaders/experiment_repeated_run_groups.py +57 -0
- phoenix/server/api/dataloaders/experiment_runs_by_experiment_and_example.py +44 -0
- phoenix/server/api/dataloaders/latency_ms_quantile.py +40 -8
- phoenix/server/api/dataloaders/record_counts.py +37 -10
- phoenix/server/api/dataloaders/session_annotations_by_session.py +29 -0
- phoenix/server/api/dataloaders/span_cost_summary_by_experiment_repeated_run_group.py +64 -0
- phoenix/server/api/dataloaders/span_cost_summary_by_project.py +28 -14
- phoenix/server/api/dataloaders/span_costs.py +3 -9
- phoenix/server/api/dataloaders/table_fields.py +2 -2
- phoenix/server/api/dataloaders/token_prices_by_model.py +30 -0
- phoenix/server/api/dataloaders/trace_annotations_by_trace.py +27 -0
- phoenix/server/api/exceptions.py +5 -1
- phoenix/server/api/helpers/playground_clients.py +263 -83
- phoenix/server/api/helpers/playground_spans.py +2 -1
- phoenix/server/api/helpers/playground_users.py +26 -0
- phoenix/server/api/helpers/prompts/conversions/google.py +103 -0
- phoenix/server/api/helpers/prompts/models.py +61 -19
- phoenix/server/api/input_types/{SpanAnnotationFilter.py → AnnotationFilter.py} +22 -14
- phoenix/server/api/input_types/ChatCompletionInput.py +3 -0
- phoenix/server/api/input_types/CreateProjectSessionAnnotationInput.py +37 -0
- phoenix/server/api/input_types/DatasetFilter.py +5 -2
- phoenix/server/api/input_types/ExperimentRunSort.py +237 -0
- phoenix/server/api/input_types/GenerativeModelInput.py +3 -0
- phoenix/server/api/input_types/ProjectSessionSort.py +158 -1
- phoenix/server/api/input_types/PromptVersionInput.py +47 -1
- phoenix/server/api/input_types/SpanSort.py +3 -2
- phoenix/server/api/input_types/UpdateAnnotationInput.py +34 -0
- phoenix/server/api/input_types/UserRoleInput.py +1 -0
- phoenix/server/api/mutations/__init__.py +8 -0
- phoenix/server/api/mutations/annotation_config_mutations.py +8 -8
- phoenix/server/api/mutations/api_key_mutations.py +15 -20
- phoenix/server/api/mutations/chat_mutations.py +106 -37
- phoenix/server/api/mutations/dataset_label_mutations.py +243 -0
- phoenix/server/api/mutations/dataset_mutations.py +21 -16
- phoenix/server/api/mutations/dataset_split_mutations.py +351 -0
- phoenix/server/api/mutations/experiment_mutations.py +2 -2
- phoenix/server/api/mutations/export_events_mutations.py +3 -3
- phoenix/server/api/mutations/model_mutations.py +11 -9
- phoenix/server/api/mutations/project_mutations.py +4 -4
- phoenix/server/api/mutations/project_session_annotations_mutations.py +158 -0
- phoenix/server/api/mutations/project_trace_retention_policy_mutations.py +8 -4
- phoenix/server/api/mutations/prompt_label_mutations.py +74 -65
- phoenix/server/api/mutations/prompt_mutations.py +65 -129
- phoenix/server/api/mutations/prompt_version_tag_mutations.py +11 -8
- phoenix/server/api/mutations/span_annotations_mutations.py +15 -10
- phoenix/server/api/mutations/trace_annotations_mutations.py +13 -8
- phoenix/server/api/mutations/trace_mutations.py +3 -3
- phoenix/server/api/mutations/user_mutations.py +55 -26
- phoenix/server/api/queries.py +501 -617
- phoenix/server/api/routers/__init__.py +2 -2
- phoenix/server/api/routers/auth.py +141 -87
- phoenix/server/api/routers/ldap.py +229 -0
- phoenix/server/api/routers/oauth2.py +349 -101
- phoenix/server/api/routers/v1/__init__.py +22 -4
- phoenix/server/api/routers/v1/annotation_configs.py +19 -30
- phoenix/server/api/routers/v1/annotations.py +455 -13
- phoenix/server/api/routers/v1/datasets.py +355 -68
- phoenix/server/api/routers/v1/documents.py +142 -0
- phoenix/server/api/routers/v1/evaluations.py +20 -28
- phoenix/server/api/routers/v1/experiment_evaluations.py +16 -6
- phoenix/server/api/routers/v1/experiment_runs.py +335 -59
- phoenix/server/api/routers/v1/experiments.py +475 -47
- phoenix/server/api/routers/v1/projects.py +16 -50
- phoenix/server/api/routers/v1/prompts.py +50 -39
- phoenix/server/api/routers/v1/sessions.py +108 -0
- phoenix/server/api/routers/v1/spans.py +156 -96
- phoenix/server/api/routers/v1/traces.py +51 -77
- phoenix/server/api/routers/v1/users.py +64 -24
- phoenix/server/api/routers/v1/utils.py +3 -7
- phoenix/server/api/subscriptions.py +257 -93
- phoenix/server/api/types/Annotation.py +90 -23
- phoenix/server/api/types/ApiKey.py +13 -17
- phoenix/server/api/types/AuthMethod.py +1 -0
- phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +1 -0
- phoenix/server/api/types/Dataset.py +199 -72
- phoenix/server/api/types/DatasetExample.py +88 -18
- phoenix/server/api/types/DatasetExperimentAnnotationSummary.py +10 -0
- phoenix/server/api/types/DatasetLabel.py +57 -0
- phoenix/server/api/types/DatasetSplit.py +98 -0
- phoenix/server/api/types/DatasetVersion.py +49 -4
- phoenix/server/api/types/DocumentAnnotation.py +212 -0
- phoenix/server/api/types/Experiment.py +215 -68
- phoenix/server/api/types/ExperimentComparison.py +3 -9
- phoenix/server/api/types/ExperimentRepeatedRunGroup.py +155 -0
- phoenix/server/api/types/ExperimentRepeatedRunGroupAnnotationSummary.py +9 -0
- phoenix/server/api/types/ExperimentRun.py +120 -70
- phoenix/server/api/types/ExperimentRunAnnotation.py +158 -39
- phoenix/server/api/types/GenerativeModel.py +95 -42
- phoenix/server/api/types/GenerativeProvider.py +1 -1
- phoenix/server/api/types/ModelInterface.py +7 -2
- phoenix/server/api/types/PlaygroundModel.py +12 -2
- phoenix/server/api/types/Project.py +218 -185
- phoenix/server/api/types/ProjectSession.py +146 -29
- phoenix/server/api/types/ProjectSessionAnnotation.py +187 -0
- phoenix/server/api/types/ProjectTraceRetentionPolicy.py +1 -1
- phoenix/server/api/types/Prompt.py +119 -39
- phoenix/server/api/types/PromptLabel.py +42 -25
- phoenix/server/api/types/PromptVersion.py +11 -8
- phoenix/server/api/types/PromptVersionTag.py +65 -25
- phoenix/server/api/types/Span.py +130 -123
- phoenix/server/api/types/SpanAnnotation.py +189 -42
- phoenix/server/api/types/SystemApiKey.py +65 -1
- phoenix/server/api/types/Trace.py +184 -53
- phoenix/server/api/types/TraceAnnotation.py +149 -50
- phoenix/server/api/types/User.py +128 -33
- phoenix/server/api/types/UserApiKey.py +73 -26
- phoenix/server/api/types/node.py +10 -0
- phoenix/server/api/types/pagination.py +11 -2
- phoenix/server/app.py +154 -36
- phoenix/server/authorization.py +5 -4
- phoenix/server/bearer_auth.py +13 -5
- phoenix/server/cost_tracking/cost_model_lookup.py +42 -14
- phoenix/server/cost_tracking/model_cost_manifest.json +1085 -194
- phoenix/server/daemons/generative_model_store.py +61 -9
- phoenix/server/daemons/span_cost_calculator.py +10 -8
- phoenix/server/dml_event.py +13 -0
- phoenix/server/email/sender.py +29 -2
- phoenix/server/grpc_server.py +9 -9
- phoenix/server/jwt_store.py +8 -6
- phoenix/server/ldap.py +1449 -0
- phoenix/server/main.py +9 -3
- phoenix/server/oauth2.py +330 -12
- phoenix/server/prometheus.py +43 -6
- phoenix/server/rate_limiters.py +4 -9
- phoenix/server/retention.py +33 -20
- phoenix/server/session_filters.py +49 -0
- phoenix/server/static/.vite/manifest.json +51 -53
- phoenix/server/static/assets/components-BreFUQQa.js +6702 -0
- phoenix/server/static/assets/{index-BPCwGQr8.js → index-CTQoemZv.js} +42 -35
- phoenix/server/static/assets/pages-DBE5iYM3.js +9524 -0
- phoenix/server/static/assets/vendor-BGzfc4EU.css +1 -0
- phoenix/server/static/assets/vendor-DCE4v-Ot.js +920 -0
- phoenix/server/static/assets/vendor-codemirror-D5f205eT.js +25 -0
- phoenix/server/static/assets/{vendor-recharts-Bw30oz1A.js → vendor-recharts-V9cwpXsm.js} +7 -7
- phoenix/server/static/assets/{vendor-shiki-DZajAPeq.js → vendor-shiki-Do--csgv.js} +1 -1
- phoenix/server/static/assets/vendor-three-CmB8bl_y.js +3840 -0
- phoenix/server/templates/index.html +7 -1
- phoenix/server/thread_server.py +1 -2
- phoenix/server/utils.py +74 -0
- phoenix/session/client.py +55 -1
- phoenix/session/data_extractor.py +5 -0
- phoenix/session/evaluation.py +8 -4
- phoenix/session/session.py +44 -8
- phoenix/settings.py +2 -0
- phoenix/trace/attributes.py +80 -13
- phoenix/trace/dsl/query.py +2 -0
- phoenix/trace/projects.py +5 -0
- phoenix/utilities/template_formatters.py +1 -1
- phoenix/version.py +1 -1
- phoenix/server/api/types/Evaluation.py +0 -39
- phoenix/server/static/assets/components-D0DWAf0l.js +0 -5650
- phoenix/server/static/assets/pages-Creyamao.js +0 -8612
- phoenix/server/static/assets/vendor-CU36oj8y.js +0 -905
- phoenix/server/static/assets/vendor-CqDb5u4o.css +0 -1
- phoenix/server/static/assets/vendor-arizeai-Ctgw0e1G.js +0 -168
- phoenix/server/static/assets/vendor-codemirror-Cojjzqb9.js +0 -25
- phoenix/server/static/assets/vendor-three-BLWp5bic.js +0 -2998
- phoenix/utilities/deprecation.py +0 -31
- {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/entry_points.txt +0 -0
- {arize_phoenix-11.23.1.dist-info → arize_phoenix-12.28.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -222,6 +222,7 @@ def get_db_experiment_run(
|
|
|
222
222
|
*,
|
|
223
223
|
experiment_id: int,
|
|
224
224
|
example_id: int,
|
|
225
|
+
repetition_number: int,
|
|
225
226
|
) -> models.ExperimentRun:
|
|
226
227
|
return models.ExperimentRun(
|
|
227
228
|
experiment_id=experiment_id,
|
|
@@ -230,7 +231,7 @@ def get_db_experiment_run(
|
|
|
230
231
|
output=models.ExperimentRunOutput(
|
|
231
232
|
task_output=get_dataset_example_output(db_span),
|
|
232
233
|
),
|
|
233
|
-
repetition_number=
|
|
234
|
+
repetition_number=repetition_number,
|
|
234
235
|
start_time=db_span.start_time,
|
|
235
236
|
end_time=db_span.end_time,
|
|
236
237
|
error=db_span.status_message or None,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
Optional,
|
|
3
|
+
)
|
|
4
|
+
|
|
5
|
+
from starlette.requests import Request
|
|
6
|
+
from strawberry import Info
|
|
7
|
+
|
|
8
|
+
from phoenix.server.api.context import Context
|
|
9
|
+
from phoenix.server.bearer_auth import PhoenixUser
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_user(info: Info[Context, None]) -> Optional[int]:
|
|
13
|
+
user_id: Optional[int] = None
|
|
14
|
+
try:
|
|
15
|
+
assert isinstance(request := info.context.request, Request)
|
|
16
|
+
|
|
17
|
+
if "user" in request.scope and isinstance((user := info.context.user), PhoenixUser):
|
|
18
|
+
user_id = int(user.identity)
|
|
19
|
+
except AssertionError:
|
|
20
|
+
# Request is not available, try to obtain user identify
|
|
21
|
+
# this will also throw an assertion error if auth is not available
|
|
22
|
+
# the finally block will continue execution returning None
|
|
23
|
+
if info.context.user.is_authenticated:
|
|
24
|
+
user_id = int(info.context.user.identity)
|
|
25
|
+
finally:
|
|
26
|
+
return user_id
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Literal, Union
|
|
2
|
+
|
|
3
|
+
from typing_extensions import NotRequired, TypedDict, assert_never
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from phoenix.server.api.helpers.prompts.models import (
|
|
7
|
+
PromptToolChoiceNone,
|
|
8
|
+
PromptToolChoiceOneOrMore,
|
|
9
|
+
PromptToolChoiceSpecificFunctionTool,
|
|
10
|
+
PromptToolChoiceZeroOrMore,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class GoogleFunctionCallingConfig(TypedDict, total=False):
|
|
15
|
+
"""
|
|
16
|
+
Based on https://github.com/googleapis/python-genai/blob/97cc7e4eafbee4fa4035e7420170ab6a2c9da7fb/google/genai/types.py#L4245
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
mode: NotRequired[Literal["auto", "any", "none"]]
|
|
20
|
+
allowed_function_names: NotRequired[list[str]]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class GoogleToolChoice(TypedDict):
|
|
24
|
+
"""
|
|
25
|
+
Based on https://github.com/googleapis/python-genai/blob/97cc7e4eafbee4fa4035e7420170ab6a2c9da7fb/google/genai/types.py#L4341
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
function_calling_config: GoogleFunctionCallingConfig
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class GoogleToolChoiceConversion:
|
|
32
|
+
@staticmethod
|
|
33
|
+
def to_google(
|
|
34
|
+
obj: Union[
|
|
35
|
+
"PromptToolChoiceNone",
|
|
36
|
+
"PromptToolChoiceZeroOrMore",
|
|
37
|
+
"PromptToolChoiceOneOrMore",
|
|
38
|
+
"PromptToolChoiceSpecificFunctionTool",
|
|
39
|
+
],
|
|
40
|
+
) -> GoogleToolChoice:
|
|
41
|
+
if obj.type == "none":
|
|
42
|
+
return {"function_calling_config": {"mode": "none"}}
|
|
43
|
+
if obj.type == "zero_or_more":
|
|
44
|
+
return {"function_calling_config": {"mode": "auto"}}
|
|
45
|
+
if obj.type == "one_or_more":
|
|
46
|
+
return {"function_calling_config": {"mode": "any"}}
|
|
47
|
+
if obj.type == "specific_function":
|
|
48
|
+
return {
|
|
49
|
+
"function_calling_config": {
|
|
50
|
+
"mode": "any",
|
|
51
|
+
"allowed_function_names": [obj.function_name],
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
assert_never(obj)
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def from_google(
|
|
58
|
+
obj: Any,
|
|
59
|
+
) -> Union[
|
|
60
|
+
"PromptToolChoiceNone",
|
|
61
|
+
"PromptToolChoiceZeroOrMore",
|
|
62
|
+
"PromptToolChoiceOneOrMore",
|
|
63
|
+
"PromptToolChoiceSpecificFunctionTool",
|
|
64
|
+
]:
|
|
65
|
+
from google.genai.types import ToolConfig
|
|
66
|
+
|
|
67
|
+
from phoenix.server.api.helpers.prompts.models import (
|
|
68
|
+
PromptToolChoiceNone,
|
|
69
|
+
PromptToolChoiceOneOrMore,
|
|
70
|
+
PromptToolChoiceSpecificFunctionTool,
|
|
71
|
+
PromptToolChoiceZeroOrMore,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
tool_config = ToolConfig.model_validate(obj)
|
|
75
|
+
if (function_calling_config := tool_config.function_calling_config) is None:
|
|
76
|
+
raise ValueError("function_calling_config is required")
|
|
77
|
+
# normalize mode to lowercase since Google's API is case-insensitive
|
|
78
|
+
# https://github.com/googleapis/python-genai/blob/97cc7e4eafbee4fa4035e7420170ab6a2c9da7fb/google/genai/types.py#L645
|
|
79
|
+
normalized_mode = (
|
|
80
|
+
function_calling_config.mode.value.lower()
|
|
81
|
+
if function_calling_config.mode is not None
|
|
82
|
+
else None
|
|
83
|
+
)
|
|
84
|
+
allowed_function_names = function_calling_config.allowed_function_names
|
|
85
|
+
|
|
86
|
+
if allowed_function_names:
|
|
87
|
+
if len(allowed_function_names) != 1:
|
|
88
|
+
raise ValueError("Only one allowed function name is currently supported")
|
|
89
|
+
if normalized_mode != "any":
|
|
90
|
+
raise ValueError("allowed function names only supported in 'any' mode")
|
|
91
|
+
return PromptToolChoiceSpecificFunctionTool(
|
|
92
|
+
type="specific_function",
|
|
93
|
+
function_name=allowed_function_names[0],
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if normalized_mode == "none":
|
|
97
|
+
return PromptToolChoiceNone(type="none")
|
|
98
|
+
if normalized_mode == "auto" or normalized_mode is None:
|
|
99
|
+
return PromptToolChoiceZeroOrMore(type="zero_or_more")
|
|
100
|
+
if normalized_mode == "any":
|
|
101
|
+
return PromptToolChoiceOneOrMore(type="one_or_more")
|
|
102
|
+
|
|
103
|
+
raise ValueError(f"Unsupported Google tool choice mode: {normalized_mode}")
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
1
|
from enum import Enum
|
|
4
2
|
from typing import Any, Literal, Mapping, Optional, Union
|
|
5
3
|
|
|
@@ -10,6 +8,7 @@ from phoenix.db.types.db_models import UNDEFINED, DBBaseModel
|
|
|
10
8
|
from phoenix.db.types.model_provider import ModelProvider
|
|
11
9
|
from phoenix.server.api.helpers.prompts.conversions.anthropic import AnthropicToolChoiceConversion
|
|
12
10
|
from phoenix.server.api.helpers.prompts.conversions.aws import AwsToolChoiceConversion
|
|
11
|
+
from phoenix.server.api.helpers.prompts.conversions.google import GoogleToolChoiceConversion
|
|
13
12
|
from phoenix.server.api.helpers.prompts.conversions.openai import OpenAIToolChoiceConversion
|
|
14
13
|
|
|
15
14
|
JSONSerializable = Union[None, bool, int, float, str, dict[str, Any], list[Any]]
|
|
@@ -127,11 +126,6 @@ class PromptTemplateRootModel(RootModel[PromptTemplate]):
|
|
|
127
126
|
root: PromptTemplate
|
|
128
127
|
|
|
129
128
|
|
|
130
|
-
class PromptToolFunction(DBBaseModel):
|
|
131
|
-
type: Literal["function"]
|
|
132
|
-
function: PromptToolFunctionDefinition
|
|
133
|
-
|
|
134
|
-
|
|
135
129
|
class PromptToolFunctionDefinition(DBBaseModel):
|
|
136
130
|
name: str
|
|
137
131
|
description: str = UNDEFINED
|
|
@@ -139,14 +133,12 @@ class PromptToolFunctionDefinition(DBBaseModel):
|
|
|
139
133
|
strict: bool = UNDEFINED
|
|
140
134
|
|
|
141
135
|
|
|
142
|
-
|
|
136
|
+
class PromptToolFunction(DBBaseModel):
|
|
137
|
+
type: Literal["function"]
|
|
138
|
+
function: PromptToolFunctionDefinition
|
|
143
139
|
|
|
144
140
|
|
|
145
|
-
|
|
146
|
-
type: Literal["tools"]
|
|
147
|
-
tools: Annotated[list[PromptTool], Field(..., min_length=1)]
|
|
148
|
-
tool_choice: PromptToolChoice = UNDEFINED
|
|
149
|
-
disable_parallel_tool_calls: bool = UNDEFINED
|
|
141
|
+
PromptTool: TypeAlias = Annotated[Union[PromptToolFunction], Field(..., discriminator="type")]
|
|
150
142
|
|
|
151
143
|
|
|
152
144
|
class PromptToolChoiceNone(DBBaseModel):
|
|
@@ -177,6 +169,13 @@ PromptToolChoice: TypeAlias = Annotated[
|
|
|
177
169
|
]
|
|
178
170
|
|
|
179
171
|
|
|
172
|
+
class PromptTools(DBBaseModel):
|
|
173
|
+
type: Literal["tools"]
|
|
174
|
+
tools: Annotated[list[PromptTool], Field(..., min_length=1)]
|
|
175
|
+
tool_choice: PromptToolChoice = UNDEFINED
|
|
176
|
+
disable_parallel_tool_calls: bool = UNDEFINED
|
|
177
|
+
|
|
178
|
+
|
|
180
179
|
class PromptOpenAIJSONSchema(DBBaseModel):
|
|
181
180
|
"""
|
|
182
181
|
Based on https://github.com/openai/openai-python/blob/d16e6edde5a155626910b5758a0b939bfedb9ced/src/openai/types/shared/response_format_json_schema.py#L13
|
|
@@ -200,11 +199,6 @@ class PromptOpenAIResponseFormatJSONSchema(DBBaseModel):
|
|
|
200
199
|
type: Literal["json_schema"]
|
|
201
200
|
|
|
202
201
|
|
|
203
|
-
class PromptResponseFormatJSONSchema(DBBaseModel):
|
|
204
|
-
type: Literal["json_schema"]
|
|
205
|
-
json_schema: PromptResponseFormatJSONSchemaDefinition
|
|
206
|
-
|
|
207
|
-
|
|
208
202
|
class PromptResponseFormatJSONSchemaDefinition(DBBaseModel):
|
|
209
203
|
name: str
|
|
210
204
|
description: str = UNDEFINED
|
|
@@ -212,6 +206,11 @@ class PromptResponseFormatJSONSchemaDefinition(DBBaseModel):
|
|
|
212
206
|
strict: bool = UNDEFINED
|
|
213
207
|
|
|
214
208
|
|
|
209
|
+
class PromptResponseFormatJSONSchema(DBBaseModel):
|
|
210
|
+
type: Literal["json_schema"]
|
|
211
|
+
json_schema: PromptResponseFormatJSONSchemaDefinition
|
|
212
|
+
|
|
213
|
+
|
|
215
214
|
PromptResponseFormat: TypeAlias = Annotated[
|
|
216
215
|
Union[PromptResponseFormatJSONSchema], Field(..., discriminator="type")
|
|
217
216
|
]
|
|
@@ -321,6 +320,16 @@ class BedrockToolDefinition(DBBaseModel):
|
|
|
321
320
|
toolSpec: dict[str, Any]
|
|
322
321
|
|
|
323
322
|
|
|
323
|
+
class GeminiToolDefinition(DBBaseModel):
|
|
324
|
+
"""
|
|
325
|
+
Based on https://github.com/googleapis/python-genai/blob/c0b175a0ca20286db419390031a2239938d0c0b7/google/genai/types.py#L2792
|
|
326
|
+
"""
|
|
327
|
+
|
|
328
|
+
name: str
|
|
329
|
+
description: str = UNDEFINED
|
|
330
|
+
parameters: dict[str, Any]
|
|
331
|
+
|
|
332
|
+
|
|
324
333
|
class PromptOpenAIInvocationParametersContent(DBBaseModel):
|
|
325
334
|
temperature: float = UNDEFINED
|
|
326
335
|
max_tokens: int = UNDEFINED
|
|
@@ -329,7 +338,7 @@ class PromptOpenAIInvocationParametersContent(DBBaseModel):
|
|
|
329
338
|
presence_penalty: float = UNDEFINED
|
|
330
339
|
top_p: float = UNDEFINED
|
|
331
340
|
seed: int = UNDEFINED
|
|
332
|
-
reasoning_effort: Literal["minimal", "low", "medium", "high"] = UNDEFINED
|
|
341
|
+
reasoning_effort: Literal["none", "minimal", "low", "medium", "high", "xhigh"] = UNDEFINED
|
|
333
342
|
|
|
334
343
|
|
|
335
344
|
class PromptOpenAIInvocationParameters(DBBaseModel):
|
|
@@ -565,6 +574,9 @@ def normalize_tools(
|
|
|
565
574
|
elif model_provider is ModelProvider.ANTHROPIC:
|
|
566
575
|
anthropic_tools = [AnthropicToolDefinition.model_validate(schema) for schema in schemas]
|
|
567
576
|
tools = [_anthropic_to_prompt_tool(anthropic_tool) for anthropic_tool in anthropic_tools]
|
|
577
|
+
elif model_provider is ModelProvider.GOOGLE:
|
|
578
|
+
gemini_tools = [GeminiToolDefinition.model_validate(schema) for schema in schemas]
|
|
579
|
+
tools = [_gemini_to_prompt_tool(gemini_tool) for gemini_tool in gemini_tools]
|
|
568
580
|
else:
|
|
569
581
|
raise ValueError(f"Unsupported model provider: {model_provider}")
|
|
570
582
|
ans = PromptTools(type="tools", tools=tools)
|
|
@@ -587,6 +599,8 @@ def normalize_tools(
|
|
|
587
599
|
ans.tool_choice = choice
|
|
588
600
|
if disable_parallel_tool_calls is not None:
|
|
589
601
|
ans.disable_parallel_tool_calls = disable_parallel_tool_calls
|
|
602
|
+
elif model_provider is ModelProvider.GOOGLE:
|
|
603
|
+
ans.tool_choice = GoogleToolChoiceConversion.from_google(tool_choice)
|
|
590
604
|
return ans
|
|
591
605
|
|
|
592
606
|
|
|
@@ -614,6 +628,10 @@ def denormalize_tools(
|
|
|
614
628
|
denormalized_tools = [_prompt_to_anthropic_tool(tool) for tool in tools.tools]
|
|
615
629
|
if tools.tool_choice and tools.tool_choice.type != "none":
|
|
616
630
|
tool_choice = AnthropicToolChoiceConversion.to_anthropic(tools.tool_choice)
|
|
631
|
+
elif model_provider is ModelProvider.GOOGLE:
|
|
632
|
+
denormalized_tools = [_prompt_to_gemini_tool(tool) for tool in tools.tools]
|
|
633
|
+
if tools.tool_choice:
|
|
634
|
+
tool_choice = GoogleToolChoiceConversion.to_google(tools.tool_choice)
|
|
617
635
|
else:
|
|
618
636
|
raise ValueError(f"Unsupported model provider: {model_provider}")
|
|
619
637
|
return [tool.model_dump() for tool in denormalized_tools], tool_choice
|
|
@@ -703,3 +721,27 @@ def _prompt_to_bedrock_tool(
|
|
|
703
721
|
},
|
|
704
722
|
}
|
|
705
723
|
)
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
def _gemini_to_prompt_tool(
|
|
727
|
+
tool: GeminiToolDefinition,
|
|
728
|
+
) -> PromptToolFunction:
|
|
729
|
+
return PromptToolFunction(
|
|
730
|
+
type="function",
|
|
731
|
+
function=PromptToolFunctionDefinition(
|
|
732
|
+
name=tool.name,
|
|
733
|
+
description=tool.description,
|
|
734
|
+
parameters=tool.parameters,
|
|
735
|
+
),
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
def _prompt_to_gemini_tool(
|
|
740
|
+
tool: PromptToolFunction,
|
|
741
|
+
) -> GeminiToolDefinition:
|
|
742
|
+
function = tool.function
|
|
743
|
+
return GeminiToolDefinition(
|
|
744
|
+
name=function.name,
|
|
745
|
+
description=function.description,
|
|
746
|
+
parameters=function.parameters,
|
|
747
|
+
)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
from typing import Optional
|
|
1
|
+
from typing import Optional, Union
|
|
2
2
|
|
|
3
3
|
import strawberry
|
|
4
4
|
from strawberry import UNSET
|
|
5
5
|
from strawberry.relay import GlobalID
|
|
6
|
+
from typing_extensions import TypeAlias
|
|
6
7
|
|
|
7
8
|
from phoenix.db import models
|
|
8
9
|
from phoenix.server.api.exceptions import BadRequest
|
|
@@ -11,7 +12,7 @@ from phoenix.server.api.types.node import from_global_id_with_expected_type
|
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
@strawberry.input
|
|
14
|
-
class
|
|
15
|
+
class AnnotationFilterCondition:
|
|
15
16
|
names: Optional[list[str]] = UNSET
|
|
16
17
|
sources: Optional[list[AnnotationSource]] = UNSET
|
|
17
18
|
user_ids: Optional[list[Optional[GlobalID]]] = UNSET
|
|
@@ -26,42 +27,49 @@ class SpanAnnotationFilterCondition:
|
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
@strawberry.input
|
|
29
|
-
class
|
|
30
|
-
include: Optional[
|
|
31
|
-
exclude: Optional[
|
|
30
|
+
class AnnotationFilter:
|
|
31
|
+
include: Optional[AnnotationFilterCondition] = UNSET
|
|
32
|
+
exclude: Optional[AnnotationFilterCondition] = UNSET
|
|
32
33
|
|
|
33
34
|
def __post_init__(self) -> None:
|
|
34
35
|
if self.include is UNSET and self.exclude is UNSET:
|
|
35
36
|
raise BadRequest("include and exclude cannot both be unset")
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
_Annotation: TypeAlias = Union[
|
|
40
|
+
models.SpanAnnotation,
|
|
41
|
+
models.TraceAnnotation,
|
|
42
|
+
models.ProjectSessionAnnotation,
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def satisfies_filter(annotation: _Annotation, filter: AnnotationFilter) -> bool:
|
|
39
47
|
"""
|
|
40
|
-
Returns true if the
|
|
48
|
+
Returns true if the annotation satisfies the filter and false otherwise.
|
|
41
49
|
"""
|
|
42
|
-
|
|
50
|
+
annotation_source = AnnotationSource(annotation.source)
|
|
43
51
|
if include := filter.include:
|
|
44
|
-
if include.names and
|
|
52
|
+
if include.names and annotation.name not in include.names:
|
|
45
53
|
return False
|
|
46
|
-
if include.sources and
|
|
54
|
+
if include.sources and annotation_source not in include.sources:
|
|
47
55
|
return False
|
|
48
56
|
if include.user_ids:
|
|
49
57
|
user_rowids = [
|
|
50
58
|
from_global_id_with_expected_type(user_id, "User") if user_id is not None else None
|
|
51
59
|
for user_id in include.user_ids
|
|
52
60
|
]
|
|
53
|
-
if
|
|
61
|
+
if annotation.user_id not in user_rowids:
|
|
54
62
|
return False
|
|
55
63
|
if exclude := filter.exclude:
|
|
56
|
-
if exclude.names and
|
|
64
|
+
if exclude.names and annotation.name in exclude.names:
|
|
57
65
|
return False
|
|
58
|
-
if exclude.sources and
|
|
66
|
+
if exclude.sources and annotation_source in exclude.sources:
|
|
59
67
|
return False
|
|
60
68
|
if exclude.user_ids:
|
|
61
69
|
user_rowids = [
|
|
62
70
|
from_global_id_with_expected_type(user_id, "User") if user_id is not None else None
|
|
63
71
|
for user_id in exclude.user_ids
|
|
64
72
|
]
|
|
65
|
-
if
|
|
73
|
+
if annotation.user_id in user_rowids:
|
|
66
74
|
return False
|
|
67
75
|
return True
|
|
@@ -26,6 +26,7 @@ class ChatCompletionInput:
|
|
|
26
26
|
credentials: Optional[list[GenerativeCredentialInput]] = UNSET
|
|
27
27
|
template: Optional[PromptTemplateOptions] = UNSET
|
|
28
28
|
prompt_name: Optional[Identifier] = None
|
|
29
|
+
repetitions: int
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
@strawberry.input
|
|
@@ -36,8 +37,10 @@ class ChatCompletionOverDatasetInput:
|
|
|
36
37
|
tools: Optional[list[JSON]] = UNSET
|
|
37
38
|
credentials: Optional[list[GenerativeCredentialInput]] = UNSET
|
|
38
39
|
template_format: PromptTemplateFormat = PromptTemplateFormat.MUSTACHE
|
|
40
|
+
repetitions: int
|
|
39
41
|
dataset_id: GlobalID
|
|
40
42
|
dataset_version_id: Optional[GlobalID] = None
|
|
43
|
+
split_ids: Optional[list[GlobalID]] = None
|
|
41
44
|
experiment_name: Optional[str] = None
|
|
42
45
|
experiment_description: Optional[str] = None
|
|
43
46
|
experiment_metadata: Optional[JSON] = strawberry.field(default_factory=dict)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from strawberry.relay import GlobalID
|
|
5
|
+
from strawberry.scalars import JSON
|
|
6
|
+
|
|
7
|
+
from phoenix.server.api.exceptions import BadRequest
|
|
8
|
+
from phoenix.server.api.types.AnnotationSource import AnnotationSource
|
|
9
|
+
from phoenix.server.api.types.AnnotatorKind import AnnotatorKind
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@strawberry.input
|
|
13
|
+
class CreateProjectSessionAnnotationInput:
|
|
14
|
+
project_session_id: GlobalID
|
|
15
|
+
name: str
|
|
16
|
+
annotator_kind: AnnotatorKind = AnnotatorKind.HUMAN
|
|
17
|
+
label: Optional[str] = None
|
|
18
|
+
score: Optional[float] = None
|
|
19
|
+
explanation: Optional[str] = None
|
|
20
|
+
metadata: JSON = strawberry.field(default_factory=dict)
|
|
21
|
+
source: AnnotationSource = AnnotationSource.APP
|
|
22
|
+
identifier: Optional[str] = strawberry.UNSET
|
|
23
|
+
|
|
24
|
+
def __post_init__(self) -> None:
|
|
25
|
+
self.name = self.name.strip()
|
|
26
|
+
if isinstance(self.label, str):
|
|
27
|
+
self.label = self.label.strip()
|
|
28
|
+
if not self.label:
|
|
29
|
+
self.label = None
|
|
30
|
+
if isinstance(self.explanation, str):
|
|
31
|
+
self.explanation = self.explanation.strip()
|
|
32
|
+
if not self.explanation:
|
|
33
|
+
self.explanation = None
|
|
34
|
+
if isinstance(self.identifier, str):
|
|
35
|
+
self.identifier = self.identifier.strip()
|
|
36
|
+
if self.score is None and not self.label and not self.explanation:
|
|
37
|
+
raise BadRequest("At least one of score, label, or explanation must be not null/empty.")
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
+
from typing import Optional
|
|
2
3
|
|
|
3
4
|
import strawberry
|
|
5
|
+
from strawberry import UNSET
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
@strawberry.enum
|
|
@@ -10,5 +12,6 @@ class DatasetFilterColumn(Enum):
|
|
|
10
12
|
|
|
11
13
|
@strawberry.input(description="A filter for datasets")
|
|
12
14
|
class DatasetFilter:
|
|
13
|
-
col: DatasetFilterColumn
|
|
14
|
-
value: str
|
|
15
|
+
col: Optional[DatasetFilterColumn] = None
|
|
16
|
+
value: Optional[str] = None
|
|
17
|
+
filter_labels: Optional[list[str]] = UNSET
|