arize-phoenix 3.16.1__py3-none-any.whl → 7.7.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-7.7.0.dist-info/METADATA +261 -0
- arize_phoenix-7.7.0.dist-info/RECORD +345 -0
- {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/WHEEL +1 -1
- arize_phoenix-7.7.0.dist-info/entry_points.txt +3 -0
- phoenix/__init__.py +86 -14
- phoenix/auth.py +309 -0
- phoenix/config.py +675 -45
- phoenix/core/model.py +32 -30
- phoenix/core/model_schema.py +102 -109
- phoenix/core/model_schema_adapter.py +48 -45
- phoenix/datetime_utils.py +24 -3
- phoenix/db/README.md +54 -0
- phoenix/db/__init__.py +4 -0
- phoenix/db/alembic.ini +85 -0
- phoenix/db/bulk_inserter.py +294 -0
- phoenix/db/engines.py +208 -0
- phoenix/db/enums.py +20 -0
- phoenix/db/facilitator.py +113 -0
- phoenix/db/helpers.py +159 -0
- phoenix/db/insertion/constants.py +2 -0
- phoenix/db/insertion/dataset.py +227 -0
- phoenix/db/insertion/document_annotation.py +171 -0
- phoenix/db/insertion/evaluation.py +191 -0
- phoenix/db/insertion/helpers.py +98 -0
- phoenix/db/insertion/span.py +193 -0
- phoenix/db/insertion/span_annotation.py +158 -0
- phoenix/db/insertion/trace_annotation.py +158 -0
- phoenix/db/insertion/types.py +256 -0
- phoenix/db/migrate.py +86 -0
- phoenix/db/migrations/data_migration_scripts/populate_project_sessions.py +199 -0
- phoenix/db/migrations/env.py +114 -0
- phoenix/db/migrations/script.py.mako +26 -0
- phoenix/db/migrations/versions/10460e46d750_datasets.py +317 -0
- phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +126 -0
- phoenix/db/migrations/versions/4ded9e43755f_create_project_sessions_table.py +66 -0
- phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py +157 -0
- phoenix/db/migrations/versions/cf03bd6bae1d_init.py +280 -0
- phoenix/db/models.py +807 -0
- phoenix/exceptions.py +5 -1
- phoenix/experiments/__init__.py +6 -0
- phoenix/experiments/evaluators/__init__.py +29 -0
- phoenix/experiments/evaluators/base.py +158 -0
- phoenix/experiments/evaluators/code_evaluators.py +184 -0
- phoenix/experiments/evaluators/llm_evaluators.py +473 -0
- phoenix/experiments/evaluators/utils.py +236 -0
- phoenix/experiments/functions.py +772 -0
- phoenix/experiments/tracing.py +86 -0
- phoenix/experiments/types.py +726 -0
- phoenix/experiments/utils.py +25 -0
- phoenix/inferences/__init__.py +0 -0
- phoenix/{datasets → inferences}/errors.py +6 -5
- phoenix/{datasets → inferences}/fixtures.py +49 -42
- phoenix/{datasets/dataset.py → inferences/inferences.py} +121 -105
- phoenix/{datasets → inferences}/schema.py +11 -11
- phoenix/{datasets → inferences}/validation.py +13 -14
- 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 +5 -4
- phoenix/metrics/binning.py +4 -3
- phoenix/metrics/metrics.py +2 -1
- phoenix/metrics/mixins.py +7 -6
- phoenix/metrics/retrieval_metrics.py +2 -1
- phoenix/metrics/timeseries.py +5 -4
- phoenix/metrics/wrappers.py +9 -3
- phoenix/pointcloud/clustering.py +5 -5
- phoenix/pointcloud/pointcloud.py +7 -5
- phoenix/pointcloud/projectors.py +5 -6
- phoenix/pointcloud/umap_parameters.py +53 -52
- phoenix/server/api/README.md +28 -0
- phoenix/server/api/auth.py +44 -0
- phoenix/server/api/context.py +152 -9
- phoenix/server/api/dataloaders/__init__.py +91 -0
- phoenix/server/api/dataloaders/annotation_summaries.py +139 -0
- phoenix/server/api/dataloaders/average_experiment_run_latency.py +54 -0
- phoenix/server/api/dataloaders/cache/__init__.py +3 -0
- phoenix/server/api/dataloaders/cache/two_tier_cache.py +68 -0
- phoenix/server/api/dataloaders/dataset_example_revisions.py +131 -0
- phoenix/server/api/dataloaders/dataset_example_spans.py +38 -0
- phoenix/server/api/dataloaders/document_evaluation_summaries.py +144 -0
- phoenix/server/api/dataloaders/document_evaluations.py +31 -0
- phoenix/server/api/dataloaders/document_retrieval_metrics.py +89 -0
- phoenix/server/api/dataloaders/experiment_annotation_summaries.py +79 -0
- phoenix/server/api/dataloaders/experiment_error_rates.py +58 -0
- phoenix/server/api/dataloaders/experiment_run_annotations.py +36 -0
- phoenix/server/api/dataloaders/experiment_run_counts.py +49 -0
- phoenix/server/api/dataloaders/experiment_sequence_number.py +44 -0
- phoenix/server/api/dataloaders/latency_ms_quantile.py +188 -0
- phoenix/server/api/dataloaders/min_start_or_max_end_times.py +85 -0
- phoenix/server/api/dataloaders/project_by_name.py +31 -0
- phoenix/server/api/dataloaders/record_counts.py +116 -0
- phoenix/server/api/dataloaders/session_io.py +79 -0
- phoenix/server/api/dataloaders/session_num_traces.py +30 -0
- phoenix/server/api/dataloaders/session_num_traces_with_error.py +32 -0
- phoenix/server/api/dataloaders/session_token_usages.py +41 -0
- phoenix/server/api/dataloaders/session_trace_latency_ms_quantile.py +55 -0
- phoenix/server/api/dataloaders/span_annotations.py +26 -0
- phoenix/server/api/dataloaders/span_dataset_examples.py +31 -0
- phoenix/server/api/dataloaders/span_descendants.py +57 -0
- phoenix/server/api/dataloaders/span_projects.py +33 -0
- phoenix/server/api/dataloaders/token_counts.py +124 -0
- phoenix/server/api/dataloaders/trace_by_trace_ids.py +25 -0
- phoenix/server/api/dataloaders/trace_root_spans.py +32 -0
- phoenix/server/api/dataloaders/user_roles.py +30 -0
- phoenix/server/api/dataloaders/users.py +33 -0
- phoenix/server/api/exceptions.py +48 -0
- phoenix/server/api/helpers/__init__.py +12 -0
- phoenix/server/api/helpers/dataset_helpers.py +217 -0
- phoenix/server/api/helpers/experiment_run_filters.py +763 -0
- phoenix/server/api/helpers/playground_clients.py +948 -0
- phoenix/server/api/helpers/playground_registry.py +70 -0
- phoenix/server/api/helpers/playground_spans.py +455 -0
- phoenix/server/api/input_types/AddExamplesToDatasetInput.py +16 -0
- phoenix/server/api/input_types/AddSpansToDatasetInput.py +14 -0
- phoenix/server/api/input_types/ChatCompletionInput.py +38 -0
- phoenix/server/api/input_types/ChatCompletionMessageInput.py +24 -0
- phoenix/server/api/input_types/ClearProjectInput.py +15 -0
- phoenix/server/api/input_types/ClusterInput.py +2 -2
- phoenix/server/api/input_types/CreateDatasetInput.py +12 -0
- phoenix/server/api/input_types/CreateSpanAnnotationInput.py +18 -0
- phoenix/server/api/input_types/CreateTraceAnnotationInput.py +18 -0
- phoenix/server/api/input_types/DataQualityMetricInput.py +5 -2
- phoenix/server/api/input_types/DatasetExampleInput.py +14 -0
- phoenix/server/api/input_types/DatasetSort.py +17 -0
- phoenix/server/api/input_types/DatasetVersionSort.py +16 -0
- phoenix/server/api/input_types/DeleteAnnotationsInput.py +7 -0
- phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +13 -0
- phoenix/server/api/input_types/DeleteDatasetInput.py +7 -0
- phoenix/server/api/input_types/DeleteExperimentsInput.py +7 -0
- phoenix/server/api/input_types/DimensionFilter.py +4 -4
- phoenix/server/api/input_types/GenerativeModelInput.py +17 -0
- phoenix/server/api/input_types/Granularity.py +1 -1
- phoenix/server/api/input_types/InvocationParameters.py +162 -0
- phoenix/server/api/input_types/PatchAnnotationInput.py +19 -0
- phoenix/server/api/input_types/PatchDatasetExamplesInput.py +35 -0
- phoenix/server/api/input_types/PatchDatasetInput.py +14 -0
- phoenix/server/api/input_types/PerformanceMetricInput.py +5 -2
- phoenix/server/api/input_types/ProjectSessionSort.py +29 -0
- phoenix/server/api/input_types/SpanAnnotationSort.py +17 -0
- phoenix/server/api/input_types/SpanSort.py +134 -69
- phoenix/server/api/input_types/TemplateOptions.py +10 -0
- phoenix/server/api/input_types/TraceAnnotationSort.py +17 -0
- phoenix/server/api/input_types/UserRoleInput.py +9 -0
- phoenix/server/api/mutations/__init__.py +28 -0
- phoenix/server/api/mutations/api_key_mutations.py +167 -0
- phoenix/server/api/mutations/chat_mutations.py +593 -0
- phoenix/server/api/mutations/dataset_mutations.py +591 -0
- phoenix/server/api/mutations/experiment_mutations.py +75 -0
- phoenix/server/api/{types/ExportEventsMutation.py → mutations/export_events_mutations.py} +21 -18
- phoenix/server/api/mutations/project_mutations.py +57 -0
- phoenix/server/api/mutations/span_annotations_mutations.py +128 -0
- phoenix/server/api/mutations/trace_annotations_mutations.py +127 -0
- phoenix/server/api/mutations/user_mutations.py +329 -0
- phoenix/server/api/openapi/__init__.py +0 -0
- phoenix/server/api/openapi/main.py +17 -0
- phoenix/server/api/openapi/schema.py +16 -0
- phoenix/server/api/queries.py +738 -0
- 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 +488 -0
- phoenix/server/api/routers/v1/__init__.py +64 -0
- phoenix/server/api/routers/v1/datasets.py +1017 -0
- phoenix/server/api/routers/v1/evaluations.py +362 -0
- phoenix/server/api/routers/v1/experiment_evaluations.py +115 -0
- phoenix/server/api/routers/v1/experiment_runs.py +167 -0
- phoenix/server/api/routers/v1/experiments.py +308 -0
- phoenix/server/api/routers/v1/pydantic_compat.py +78 -0
- phoenix/server/api/routers/v1/spans.py +267 -0
- phoenix/server/api/routers/v1/traces.py +208 -0
- phoenix/server/api/routers/v1/utils.py +95 -0
- phoenix/server/api/schema.py +44 -241
- phoenix/server/api/subscriptions.py +597 -0
- phoenix/server/api/types/Annotation.py +21 -0
- phoenix/server/api/types/AnnotationSummary.py +55 -0
- phoenix/server/api/types/AnnotatorKind.py +16 -0
- phoenix/server/api/types/ApiKey.py +27 -0
- phoenix/server/api/types/AuthMethod.py +9 -0
- phoenix/server/api/types/ChatCompletionMessageRole.py +11 -0
- phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +46 -0
- phoenix/server/api/types/Cluster.py +25 -24
- phoenix/server/api/types/CreateDatasetPayload.py +8 -0
- phoenix/server/api/types/DataQualityMetric.py +31 -13
- phoenix/server/api/types/Dataset.py +288 -63
- phoenix/server/api/types/DatasetExample.py +85 -0
- phoenix/server/api/types/DatasetExampleRevision.py +34 -0
- phoenix/server/api/types/DatasetVersion.py +14 -0
- phoenix/server/api/types/Dimension.py +32 -31
- phoenix/server/api/types/DocumentEvaluationSummary.py +9 -8
- phoenix/server/api/types/EmbeddingDimension.py +56 -49
- phoenix/server/api/types/Evaluation.py +25 -31
- phoenix/server/api/types/EvaluationSummary.py +30 -50
- phoenix/server/api/types/Event.py +20 -20
- phoenix/server/api/types/ExampleRevisionInterface.py +14 -0
- phoenix/server/api/types/Experiment.py +152 -0
- phoenix/server/api/types/ExperimentAnnotationSummary.py +13 -0
- phoenix/server/api/types/ExperimentComparison.py +17 -0
- phoenix/server/api/types/ExperimentRun.py +119 -0
- phoenix/server/api/types/ExperimentRunAnnotation.py +56 -0
- phoenix/server/api/types/GenerativeModel.py +9 -0
- phoenix/server/api/types/GenerativeProvider.py +85 -0
- phoenix/server/api/types/Inferences.py +80 -0
- phoenix/server/api/types/InferencesRole.py +23 -0
- phoenix/server/api/types/LabelFraction.py +7 -0
- phoenix/server/api/types/MimeType.py +2 -2
- phoenix/server/api/types/Model.py +54 -54
- phoenix/server/api/types/PerformanceMetric.py +8 -5
- phoenix/server/api/types/Project.py +407 -142
- phoenix/server/api/types/ProjectSession.py +139 -0
- phoenix/server/api/types/Segments.py +4 -4
- phoenix/server/api/types/Span.py +221 -176
- phoenix/server/api/types/SpanAnnotation.py +43 -0
- phoenix/server/api/types/SpanIOValue.py +15 -0
- phoenix/server/api/types/SystemApiKey.py +9 -0
- phoenix/server/api/types/TemplateLanguage.py +10 -0
- phoenix/server/api/types/TimeSeries.py +19 -15
- phoenix/server/api/types/TokenUsage.py +11 -0
- phoenix/server/api/types/Trace.py +154 -0
- phoenix/server/api/types/TraceAnnotation.py +45 -0
- phoenix/server/api/types/UMAPPoints.py +7 -7
- phoenix/server/api/types/User.py +60 -0
- phoenix/server/api/types/UserApiKey.py +45 -0
- phoenix/server/api/types/UserRole.py +15 -0
- phoenix/server/api/types/node.py +4 -112
- phoenix/server/api/types/pagination.py +156 -57
- phoenix/server/api/utils.py +34 -0
- phoenix/server/app.py +864 -115
- phoenix/server/bearer_auth.py +163 -0
- phoenix/server/dml_event.py +136 -0
- phoenix/server/dml_event_handler.py +256 -0
- phoenix/server/email/__init__.py +0 -0
- phoenix/server/email/sender.py +97 -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 +102 -0
- phoenix/server/jwt_store.py +505 -0
- phoenix/server/main.py +305 -116
- phoenix/server/oauth2.py +52 -0
- phoenix/server/openapi/__init__.py +0 -0
- phoenix/server/prometheus.py +111 -0
- phoenix/server/rate_limiters.py +188 -0
- phoenix/server/static/.vite/manifest.json +87 -0
- phoenix/server/static/assets/components-Cy9nwIvF.js +2125 -0
- phoenix/server/static/assets/index-BKvHIxkk.js +113 -0
- phoenix/server/static/assets/pages-CUi2xCVQ.js +4449 -0
- phoenix/server/static/assets/vendor-DvC8cT4X.js +894 -0
- phoenix/server/static/assets/vendor-DxkFTwjz.css +1 -0
- phoenix/server/static/assets/vendor-arizeai-Do1793cv.js +662 -0
- phoenix/server/static/assets/vendor-codemirror-BzwZPyJM.js +24 -0
- phoenix/server/static/assets/vendor-recharts-_Jb7JjhG.js +59 -0
- phoenix/server/static/assets/vendor-shiki-Cl9QBraO.js +5 -0
- phoenix/server/static/assets/vendor-three-DwGkEfCM.js +2998 -0
- phoenix/server/telemetry.py +68 -0
- phoenix/server/templates/index.html +82 -23
- phoenix/server/thread_server.py +3 -3
- phoenix/server/types.py +275 -0
- phoenix/services.py +27 -18
- phoenix/session/client.py +743 -68
- phoenix/session/data_extractor.py +31 -7
- phoenix/session/evaluation.py +3 -9
- phoenix/session/session.py +263 -219
- phoenix/settings.py +22 -0
- phoenix/trace/__init__.py +2 -22
- phoenix/trace/attributes.py +338 -0
- phoenix/trace/dsl/README.md +116 -0
- phoenix/trace/dsl/filter.py +663 -213
- phoenix/trace/dsl/helpers.py +73 -21
- phoenix/trace/dsl/query.py +574 -201
- phoenix/trace/exporter.py +24 -19
- phoenix/trace/fixtures.py +368 -32
- phoenix/trace/otel.py +71 -219
- phoenix/trace/projects.py +3 -2
- phoenix/trace/schemas.py +33 -11
- phoenix/trace/span_evaluations.py +21 -16
- phoenix/trace/span_json_decoder.py +6 -4
- phoenix/trace/span_json_encoder.py +2 -2
- phoenix/trace/trace_dataset.py +47 -32
- phoenix/trace/utils.py +21 -4
- phoenix/utilities/__init__.py +0 -26
- phoenix/utilities/client.py +132 -0
- phoenix/utilities/deprecation.py +31 -0
- phoenix/utilities/error_handling.py +3 -2
- phoenix/utilities/json.py +109 -0
- phoenix/utilities/logging.py +8 -0
- phoenix/utilities/project.py +2 -2
- phoenix/utilities/re.py +49 -0
- phoenix/utilities/span_store.py +0 -23
- phoenix/utilities/template_formatters.py +99 -0
- phoenix/version.py +1 -1
- arize_phoenix-3.16.1.dist-info/METADATA +0 -495
- arize_phoenix-3.16.1.dist-info/RECORD +0 -178
- phoenix/core/project.py +0 -619
- phoenix/core/traces.py +0 -96
- phoenix/experimental/evals/__init__.py +0 -73
- phoenix/experimental/evals/evaluators.py +0 -413
- phoenix/experimental/evals/functions/__init__.py +0 -4
- phoenix/experimental/evals/functions/classify.py +0 -453
- phoenix/experimental/evals/functions/executor.py +0 -353
- phoenix/experimental/evals/functions/generate.py +0 -138
- phoenix/experimental/evals/functions/processing.py +0 -76
- phoenix/experimental/evals/models/__init__.py +0 -14
- phoenix/experimental/evals/models/anthropic.py +0 -175
- phoenix/experimental/evals/models/base.py +0 -170
- phoenix/experimental/evals/models/bedrock.py +0 -221
- phoenix/experimental/evals/models/litellm.py +0 -134
- phoenix/experimental/evals/models/openai.py +0 -448
- phoenix/experimental/evals/models/rate_limiters.py +0 -246
- phoenix/experimental/evals/models/vertex.py +0 -173
- phoenix/experimental/evals/models/vertexai.py +0 -186
- phoenix/experimental/evals/retrievals.py +0 -96
- phoenix/experimental/evals/templates/__init__.py +0 -50
- phoenix/experimental/evals/templates/default_templates.py +0 -472
- phoenix/experimental/evals/templates/template.py +0 -195
- phoenix/experimental/evals/utils/__init__.py +0 -172
- phoenix/experimental/evals/utils/threads.py +0 -27
- phoenix/server/api/helpers.py +0 -11
- phoenix/server/api/routers/evaluation_handler.py +0 -109
- phoenix/server/api/routers/span_handler.py +0 -70
- phoenix/server/api/routers/trace_handler.py +0 -60
- phoenix/server/api/types/DatasetRole.py +0 -23
- phoenix/server/static/index.css +0 -6
- phoenix/server/static/index.js +0 -7447
- phoenix/storage/span_store/__init__.py +0 -23
- phoenix/storage/span_store/text_file.py +0 -85
- phoenix/trace/dsl/missing.py +0 -60
- 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 -102
- phoenix/trace/openai/__init__.py +0 -3
- phoenix/trace/openai/instrumentor.py +0 -30
- {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/IP_NOTICE +0 -0
- {arize_phoenix-3.16.1.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/LICENSE +0 -0
- /phoenix/{datasets → db/insertion}/__init__.py +0 -0
- /phoenix/{experimental → db/migrations}/__init__.py +0 -0
- /phoenix/{storage → db/migrations/data_migration_scripts}/__init__.py +0 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
|
|
2
|
+
|
|
3
|
+
from phoenix.server.api.types.GenerativeProvider import GenerativeProviderKey
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from phoenix.server.api.helpers.playground_clients import PlaygroundStreamingClient
|
|
7
|
+
|
|
8
|
+
ModelName = Union[str, None]
|
|
9
|
+
ModelKey = tuple[GenerativeProviderKey, ModelName]
|
|
10
|
+
|
|
11
|
+
PROVIDER_DEFAULT = None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SingletonMeta(type):
|
|
15
|
+
_instances: dict[Any, Any] = dict()
|
|
16
|
+
|
|
17
|
+
def __call__(cls, *args: Any, **kwargs: Any) -> Any:
|
|
18
|
+
if cls not in cls._instances:
|
|
19
|
+
cls._instances[cls] = super(SingletonMeta, cls).__call__(*args, **kwargs)
|
|
20
|
+
return cls._instances[cls]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PlaygroundClientRegistry(metaclass=SingletonMeta):
|
|
24
|
+
def __init__(self) -> None:
|
|
25
|
+
self._registry: dict[
|
|
26
|
+
GenerativeProviderKey, dict[ModelName, Optional[type["PlaygroundStreamingClient"]]]
|
|
27
|
+
] = {}
|
|
28
|
+
|
|
29
|
+
def get_client(
|
|
30
|
+
self,
|
|
31
|
+
provider_key: GenerativeProviderKey,
|
|
32
|
+
model_name: ModelName,
|
|
33
|
+
) -> Optional[type["PlaygroundStreamingClient"]]:
|
|
34
|
+
provider_registry = self._registry.get(provider_key, {})
|
|
35
|
+
client_class = provider_registry.get(model_name)
|
|
36
|
+
if client_class is None and None in provider_registry:
|
|
37
|
+
client_class = provider_registry[PROVIDER_DEFAULT] # Fallback to provider default
|
|
38
|
+
return client_class
|
|
39
|
+
|
|
40
|
+
def list_all_providers(
|
|
41
|
+
self,
|
|
42
|
+
) -> list[GenerativeProviderKey]:
|
|
43
|
+
return [provider_key for provider_key in self._registry]
|
|
44
|
+
|
|
45
|
+
def list_models(self, provider_key: GenerativeProviderKey) -> list[str]:
|
|
46
|
+
provider_registry = self._registry.get(provider_key, {})
|
|
47
|
+
return [model_name for model_name in provider_registry.keys() if model_name is not None]
|
|
48
|
+
|
|
49
|
+
def list_all_models(self) -> list[ModelKey]:
|
|
50
|
+
return [
|
|
51
|
+
(provider_key, model_name)
|
|
52
|
+
for provider_key, provider_registry in self._registry.items()
|
|
53
|
+
for model_name in provider_registry.keys()
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
PLAYGROUND_CLIENT_REGISTRY: PlaygroundClientRegistry = PlaygroundClientRegistry()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def register_llm_client(
|
|
61
|
+
provider_key: GenerativeProviderKey,
|
|
62
|
+
model_names: list[ModelName],
|
|
63
|
+
) -> Callable[[type["PlaygroundStreamingClient"]], type["PlaygroundStreamingClient"]]:
|
|
64
|
+
def decorator(cls: type["PlaygroundStreamingClient"]) -> type["PlaygroundStreamingClient"]:
|
|
65
|
+
provider_registry = PLAYGROUND_CLIENT_REGISTRY._registry.setdefault(provider_key, {})
|
|
66
|
+
for model_name in model_names:
|
|
67
|
+
provider_registry[model_name] = cls
|
|
68
|
+
return cls
|
|
69
|
+
|
|
70
|
+
return decorator
|
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from dataclasses import asdict
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
from itertools import chain
|
|
7
|
+
from traceback import format_exc
|
|
8
|
+
from types import TracebackType
|
|
9
|
+
from typing import (
|
|
10
|
+
Any,
|
|
11
|
+
Iterable,
|
|
12
|
+
Iterator,
|
|
13
|
+
Optional,
|
|
14
|
+
Union,
|
|
15
|
+
cast,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from openinference.instrumentation import safe_json_dumps
|
|
19
|
+
from openinference.semconv.trace import (
|
|
20
|
+
MessageAttributes,
|
|
21
|
+
OpenInferenceMimeTypeValues,
|
|
22
|
+
OpenInferenceSpanKindValues,
|
|
23
|
+
SpanAttributes,
|
|
24
|
+
ToolAttributes,
|
|
25
|
+
ToolCallAttributes,
|
|
26
|
+
)
|
|
27
|
+
from opentelemetry.sdk.trace.id_generator import RandomIdGenerator as DefaultOTelIDGenerator
|
|
28
|
+
from opentelemetry.trace import StatusCode
|
|
29
|
+
from strawberry.scalars import JSON as JSONScalarType
|
|
30
|
+
from typing_extensions import Self, TypeAlias, assert_never
|
|
31
|
+
|
|
32
|
+
from phoenix.datetime_utils import local_now, normalize_datetime
|
|
33
|
+
from phoenix.db import models
|
|
34
|
+
from phoenix.server.api.helpers.dataset_helpers import get_dataset_example_output
|
|
35
|
+
from phoenix.server.api.input_types.ChatCompletionInput import (
|
|
36
|
+
ChatCompletionInput,
|
|
37
|
+
ChatCompletionOverDatasetInput,
|
|
38
|
+
)
|
|
39
|
+
from phoenix.server.api.types.ChatCompletionMessageRole import ChatCompletionMessageRole
|
|
40
|
+
from phoenix.server.api.types.ChatCompletionSubscriptionPayload import (
|
|
41
|
+
TextChunk,
|
|
42
|
+
ToolCallChunk,
|
|
43
|
+
)
|
|
44
|
+
from phoenix.trace.attributes import get_attribute_value, unflatten
|
|
45
|
+
from phoenix.trace.schemas import (
|
|
46
|
+
SpanEvent,
|
|
47
|
+
SpanException,
|
|
48
|
+
)
|
|
49
|
+
from phoenix.utilities.json import jsonify
|
|
50
|
+
|
|
51
|
+
ChatCompletionMessage: TypeAlias = tuple[
|
|
52
|
+
ChatCompletionMessageRole, str, Optional[str], Optional[list[str]]
|
|
53
|
+
]
|
|
54
|
+
ToolCallID: TypeAlias = str
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class streaming_llm_span:
|
|
58
|
+
"""
|
|
59
|
+
A context manager that records OpenInference attributes for streaming chat
|
|
60
|
+
completion LLM spans.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(
|
|
64
|
+
self,
|
|
65
|
+
*,
|
|
66
|
+
input: Union[ChatCompletionInput, ChatCompletionOverDatasetInput],
|
|
67
|
+
messages: list[ChatCompletionMessage],
|
|
68
|
+
invocation_parameters: Mapping[str, Any],
|
|
69
|
+
attributes: Optional[dict[str, Any]] = None,
|
|
70
|
+
) -> None:
|
|
71
|
+
self._input = input
|
|
72
|
+
self._attributes: dict[str, Any] = attributes if attributes is not None else {}
|
|
73
|
+
self._attributes.update(
|
|
74
|
+
chain(
|
|
75
|
+
llm_span_kind(),
|
|
76
|
+
llm_model_name(input.model.name),
|
|
77
|
+
llm_tools(input.tools or []),
|
|
78
|
+
llm_input_messages(messages),
|
|
79
|
+
llm_invocation_parameters(invocation_parameters),
|
|
80
|
+
input_value_and_mime_type(input),
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
self._events: list[SpanEvent] = []
|
|
84
|
+
self._start_time: Optional[datetime] = None
|
|
85
|
+
self._end_time: Optional[datetime] = None
|
|
86
|
+
self._text_chunks: list[TextChunk] = []
|
|
87
|
+
self._tool_call_chunks: defaultdict[ToolCallID, list[ToolCallChunk]] = defaultdict(list)
|
|
88
|
+
self._status_code: StatusCode = StatusCode.UNSET
|
|
89
|
+
self._status_message: Optional[str] = None
|
|
90
|
+
self._trace_id = _generate_trace_id()
|
|
91
|
+
self._span_id = _generate_span_id()
|
|
92
|
+
|
|
93
|
+
async def __aenter__(self) -> Self:
|
|
94
|
+
self._start_time = cast(datetime, normalize_datetime(dt=local_now(), tz=timezone.utc))
|
|
95
|
+
return self
|
|
96
|
+
|
|
97
|
+
async def __aexit__(
|
|
98
|
+
self,
|
|
99
|
+
exc_type: Optional[type[BaseException]],
|
|
100
|
+
exc_value: Optional[BaseException],
|
|
101
|
+
traceback: Optional[TracebackType],
|
|
102
|
+
) -> bool:
|
|
103
|
+
self._end_time = cast(datetime, normalize_datetime(dt=local_now(), tz=timezone.utc))
|
|
104
|
+
self._status_code = StatusCode.OK
|
|
105
|
+
if exc_type is not None:
|
|
106
|
+
self._status_code = StatusCode.ERROR
|
|
107
|
+
self._status_message = str(exc_value)
|
|
108
|
+
self._events.append(
|
|
109
|
+
SpanException(
|
|
110
|
+
timestamp=self._end_time,
|
|
111
|
+
message=self._status_message,
|
|
112
|
+
exception_type=type(exc_value).__name__,
|
|
113
|
+
exception_escaped=False,
|
|
114
|
+
exception_stacktrace=format_exc(),
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
if self._text_chunks or self._tool_call_chunks:
|
|
118
|
+
self._attributes.update(
|
|
119
|
+
chain(
|
|
120
|
+
_output_value_and_mime_type(self._text_chunks, self._tool_call_chunks),
|
|
121
|
+
_llm_output_messages(self._text_chunks, self._tool_call_chunks),
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
return True
|
|
125
|
+
|
|
126
|
+
def set_attributes(self, attributes: Mapping[str, Any]) -> None:
|
|
127
|
+
self._attributes.update(attributes)
|
|
128
|
+
|
|
129
|
+
def add_response_chunk(self, chunk: Union[TextChunk, ToolCallChunk]) -> None:
|
|
130
|
+
if isinstance(chunk, TextChunk):
|
|
131
|
+
self._text_chunks.append(chunk)
|
|
132
|
+
elif isinstance(chunk, ToolCallChunk):
|
|
133
|
+
self._tool_call_chunks[chunk.id].append(chunk)
|
|
134
|
+
else:
|
|
135
|
+
assert_never(chunk)
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def span_id(self) -> str:
|
|
139
|
+
return self._span_id
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def trace_id(self) -> str:
|
|
143
|
+
return self._trace_id
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def start_time(self) -> datetime:
|
|
147
|
+
if self._start_time is None:
|
|
148
|
+
raise ValueError("Cannot access start time before the context manager is entered")
|
|
149
|
+
return self._start_time
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def end_time(self) -> datetime:
|
|
153
|
+
if self._end_time is None:
|
|
154
|
+
raise ValueError("Cannot access end time before the context manager is exited")
|
|
155
|
+
return self._end_time
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def status_code(self) -> StatusCode:
|
|
159
|
+
return self._status_code
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def status_message(self) -> Optional[str]:
|
|
163
|
+
if self._status_code is StatusCode.UNSET:
|
|
164
|
+
raise ValueError("Cannot access status message before the context manager is exited")
|
|
165
|
+
return self._status_message
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def events(self) -> list[SpanEvent]:
|
|
169
|
+
return self._events
|
|
170
|
+
|
|
171
|
+
@property
|
|
172
|
+
def attributes(self) -> dict[str, Any]:
|
|
173
|
+
return unflatten(self._attributes.items())
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def get_db_trace(span: streaming_llm_span, project_id: int) -> models.Trace:
|
|
177
|
+
return models.Trace(
|
|
178
|
+
project_rowid=project_id,
|
|
179
|
+
trace_id=span.trace_id,
|
|
180
|
+
start_time=span.start_time,
|
|
181
|
+
end_time=span.end_time,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def get_db_span(
|
|
186
|
+
span: streaming_llm_span,
|
|
187
|
+
db_trace: models.Trace,
|
|
188
|
+
) -> models.Span:
|
|
189
|
+
prompt_tokens = get_attribute_value(span.attributes, LLM_TOKEN_COUNT_PROMPT) or 0
|
|
190
|
+
completion_tokens = get_attribute_value(span.attributes, LLM_TOKEN_COUNT_COMPLETION) or 0
|
|
191
|
+
return models.Span(
|
|
192
|
+
trace_rowid=db_trace.id,
|
|
193
|
+
span_id=span.span_id,
|
|
194
|
+
parent_id=None,
|
|
195
|
+
name="ChatCompletion",
|
|
196
|
+
span_kind=LLM,
|
|
197
|
+
start_time=span.start_time,
|
|
198
|
+
end_time=span.end_time,
|
|
199
|
+
attributes=span.attributes,
|
|
200
|
+
events=[_serialize_event(event) for event in span.events],
|
|
201
|
+
status_code=span.status_code.name,
|
|
202
|
+
status_message=span.status_message or "",
|
|
203
|
+
cumulative_error_count=int(span.status_code is StatusCode.ERROR),
|
|
204
|
+
cumulative_llm_token_count_prompt=prompt_tokens,
|
|
205
|
+
cumulative_llm_token_count_completion=completion_tokens,
|
|
206
|
+
llm_token_count_prompt=prompt_tokens,
|
|
207
|
+
llm_token_count_completion=completion_tokens,
|
|
208
|
+
trace=db_trace,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def get_db_experiment_run(
|
|
213
|
+
db_span: models.Span,
|
|
214
|
+
db_trace: models.Trace,
|
|
215
|
+
*,
|
|
216
|
+
experiment_id: int,
|
|
217
|
+
example_id: int,
|
|
218
|
+
) -> models.ExperimentRun:
|
|
219
|
+
return models.ExperimentRun(
|
|
220
|
+
experiment_id=experiment_id,
|
|
221
|
+
dataset_example_id=example_id,
|
|
222
|
+
trace_id=db_trace.trace_id,
|
|
223
|
+
output=models.ExperimentRunOutput(
|
|
224
|
+
task_output=get_dataset_example_output(db_span),
|
|
225
|
+
),
|
|
226
|
+
repetition_number=1,
|
|
227
|
+
start_time=db_span.start_time,
|
|
228
|
+
end_time=db_span.end_time,
|
|
229
|
+
error=db_span.status_message or None,
|
|
230
|
+
prompt_token_count=get_attribute_value(db_span.attributes, LLM_TOKEN_COUNT_PROMPT),
|
|
231
|
+
completion_token_count=get_attribute_value(db_span.attributes, LLM_TOKEN_COUNT_COMPLETION),
|
|
232
|
+
trace=db_trace,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def llm_span_kind() -> Iterator[tuple[str, Any]]:
|
|
237
|
+
yield OPENINFERENCE_SPAN_KIND, LLM
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def llm_model_name(model_name: str) -> Iterator[tuple[str, Any]]:
|
|
241
|
+
yield LLM_MODEL_NAME, model_name
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def llm_invocation_parameters(
|
|
245
|
+
invocation_parameters: Mapping[str, Any],
|
|
246
|
+
) -> Iterator[tuple[str, Any]]:
|
|
247
|
+
if invocation_parameters:
|
|
248
|
+
yield LLM_INVOCATION_PARAMETERS, safe_json_dumps(invocation_parameters)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def llm_tools(tools: list[JSONScalarType]) -> Iterator[tuple[str, Any]]:
|
|
252
|
+
for tool_index, tool in enumerate(tools):
|
|
253
|
+
yield f"{LLM_TOOLS}.{tool_index}.{TOOL_JSON_SCHEMA}", json.dumps(tool)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def input_value_and_mime_type(
|
|
257
|
+
input: Union[ChatCompletionInput, ChatCompletionOverDatasetInput],
|
|
258
|
+
) -> Iterator[tuple[str, Any]]:
|
|
259
|
+
assert (api_key := "api_key") in (input_data := jsonify(input))
|
|
260
|
+
disallowed_keys = {"api_key", "invocation_parameters"}
|
|
261
|
+
input_data = {k: v for k, v in input_data.items() if k not in disallowed_keys}
|
|
262
|
+
assert api_key not in input_data
|
|
263
|
+
yield INPUT_MIME_TYPE, JSON
|
|
264
|
+
yield INPUT_VALUE, safe_json_dumps(input_data)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _merge_tool_call_chunks(
|
|
268
|
+
chunks_by_id: defaultdict[str, list[ToolCallChunk]],
|
|
269
|
+
) -> list[dict[str, Any]]:
|
|
270
|
+
merged_tool_calls = []
|
|
271
|
+
|
|
272
|
+
for tool_id, chunks in chunks_by_id.items():
|
|
273
|
+
if not chunks:
|
|
274
|
+
continue
|
|
275
|
+
first_chunk = chunks[0]
|
|
276
|
+
if not first_chunk:
|
|
277
|
+
continue
|
|
278
|
+
|
|
279
|
+
if not hasattr(first_chunk, "function") or not hasattr(first_chunk.function, "name"):
|
|
280
|
+
continue
|
|
281
|
+
# Combine all argument chunks
|
|
282
|
+
merged_arguments = "".join(
|
|
283
|
+
chunk.function.arguments
|
|
284
|
+
for chunk in chunks
|
|
285
|
+
if chunk and hasattr(chunk, "function") and hasattr(chunk.function, "arguments")
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
merged_tool_calls.append(
|
|
289
|
+
{
|
|
290
|
+
"id": tool_id,
|
|
291
|
+
# Only the first chunk has the tool name
|
|
292
|
+
"function": {
|
|
293
|
+
"name": first_chunk.function.name,
|
|
294
|
+
"arguments": merged_arguments or "{}",
|
|
295
|
+
},
|
|
296
|
+
}
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
return merged_tool_calls
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _output_value_and_mime_type(
|
|
303
|
+
text_chunks: list[TextChunk],
|
|
304
|
+
tool_call_chunks: defaultdict[ToolCallID, list[ToolCallChunk]],
|
|
305
|
+
) -> Iterator[tuple[str, Any]]:
|
|
306
|
+
content = "".join(chunk.content for chunk in text_chunks)
|
|
307
|
+
merged_tool_calls = _merge_tool_call_chunks(tool_call_chunks)
|
|
308
|
+
if content and merged_tool_calls:
|
|
309
|
+
yield OUTPUT_MIME_TYPE, JSON
|
|
310
|
+
yield (
|
|
311
|
+
OUTPUT_VALUE,
|
|
312
|
+
safe_json_dumps(
|
|
313
|
+
{
|
|
314
|
+
"content": content,
|
|
315
|
+
"tool_calls": jsonify(
|
|
316
|
+
merged_tool_calls,
|
|
317
|
+
),
|
|
318
|
+
}
|
|
319
|
+
),
|
|
320
|
+
)
|
|
321
|
+
elif merged_tool_calls:
|
|
322
|
+
yield OUTPUT_MIME_TYPE, JSON
|
|
323
|
+
yield OUTPUT_VALUE, safe_json_dumps(jsonify(merged_tool_calls))
|
|
324
|
+
elif content:
|
|
325
|
+
yield OUTPUT_MIME_TYPE, TEXT
|
|
326
|
+
yield OUTPUT_VALUE, content
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def llm_input_messages(
|
|
330
|
+
messages: Iterable[
|
|
331
|
+
tuple[ChatCompletionMessageRole, str, Optional[str], Optional[list[JSONScalarType]]]
|
|
332
|
+
],
|
|
333
|
+
) -> Iterator[tuple[str, Any]]:
|
|
334
|
+
for i, (role, content, tool_call_id, tool_calls) in enumerate(messages):
|
|
335
|
+
yield f"{LLM_INPUT_MESSAGES}.{i}.{MESSAGE_ROLE}", role.value.lower()
|
|
336
|
+
yield f"{LLM_INPUT_MESSAGES}.{i}.{MESSAGE_CONTENT}", content
|
|
337
|
+
if role == ChatCompletionMessageRole.TOOL and tool_call_id:
|
|
338
|
+
# Anthropic tool result spans
|
|
339
|
+
yield f"{LLM_INPUT_MESSAGES}.{i}.{MESSAGE_TOOL_CALL_ID}", tool_call_id
|
|
340
|
+
|
|
341
|
+
if tool_calls is not None:
|
|
342
|
+
for tool_call_index, tool_call in enumerate(tool_calls):
|
|
343
|
+
if tool_call.get("type") == "tool_use":
|
|
344
|
+
# Anthropic tool call spans
|
|
345
|
+
yield (
|
|
346
|
+
f"{LLM_INPUT_MESSAGES}.{i}.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_FUNCTION_NAME}",
|
|
347
|
+
tool_call["name"],
|
|
348
|
+
)
|
|
349
|
+
yield (
|
|
350
|
+
f"{LLM_INPUT_MESSAGES}.{i}.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_FUNCTION_ARGUMENTS_JSON}",
|
|
351
|
+
safe_json_dumps(jsonify(tool_call["input"])),
|
|
352
|
+
)
|
|
353
|
+
yield (
|
|
354
|
+
f"{LLM_INPUT_MESSAGES}.{i}.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_ID}",
|
|
355
|
+
tool_call["id"],
|
|
356
|
+
)
|
|
357
|
+
elif tool_call_function := tool_call.get("function"):
|
|
358
|
+
# OpenAI tool call spans
|
|
359
|
+
yield (
|
|
360
|
+
f"{LLM_INPUT_MESSAGES}.{i}.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_FUNCTION_NAME}",
|
|
361
|
+
tool_call_function["name"],
|
|
362
|
+
)
|
|
363
|
+
if arguments := tool_call_function["arguments"]:
|
|
364
|
+
yield (
|
|
365
|
+
f"{LLM_INPUT_MESSAGES}.{i}.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_FUNCTION_ARGUMENTS_JSON}",
|
|
366
|
+
safe_json_dumps(jsonify(arguments)),
|
|
367
|
+
)
|
|
368
|
+
if tool_call_id := tool_call.get("id"):
|
|
369
|
+
yield (
|
|
370
|
+
f"{LLM_INPUT_MESSAGES}.{i}.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_ID}",
|
|
371
|
+
tool_call_id,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def _llm_output_messages(
|
|
376
|
+
text_chunks: list[TextChunk],
|
|
377
|
+
tool_call_chunks: defaultdict[ToolCallID, list[ToolCallChunk]],
|
|
378
|
+
) -> Iterator[tuple[str, Any]]:
|
|
379
|
+
yield f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_ROLE}", "assistant"
|
|
380
|
+
if content := "".join(chunk.content for chunk in text_chunks):
|
|
381
|
+
yield f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_CONTENT}", content
|
|
382
|
+
for tool_call_index, (_tool_call_id, tool_call_chunks_) in enumerate(tool_call_chunks.items()):
|
|
383
|
+
if _tool_call_id:
|
|
384
|
+
yield (
|
|
385
|
+
f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_ID}",
|
|
386
|
+
_tool_call_id,
|
|
387
|
+
)
|
|
388
|
+
if tool_call_chunks_ and (name := tool_call_chunks_[0].function.name):
|
|
389
|
+
yield (
|
|
390
|
+
f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_FUNCTION_NAME}",
|
|
391
|
+
name,
|
|
392
|
+
)
|
|
393
|
+
if arguments := "".join(chunk.function.arguments for chunk in tool_call_chunks_):
|
|
394
|
+
yield (
|
|
395
|
+
f"{LLM_OUTPUT_MESSAGES}.0.{MESSAGE_TOOL_CALLS}.{tool_call_index}.{TOOL_CALL_FUNCTION_ARGUMENTS_JSON}",
|
|
396
|
+
arguments,
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def _generate_trace_id() -> str:
|
|
401
|
+
"""
|
|
402
|
+
Generates a random trace ID in hexadecimal format.
|
|
403
|
+
"""
|
|
404
|
+
return _hex(DefaultOTelIDGenerator().generate_trace_id())
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def _generate_span_id() -> str:
|
|
408
|
+
"""
|
|
409
|
+
Generates a random span ID in hexadecimal format.
|
|
410
|
+
"""
|
|
411
|
+
return _hex(DefaultOTelIDGenerator().generate_span_id())
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def _hex(number: int) -> str:
|
|
415
|
+
"""
|
|
416
|
+
Converts an integer to a hexadecimal string.
|
|
417
|
+
"""
|
|
418
|
+
return hex(number)[2:]
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def _serialize_event(event: SpanEvent) -> dict[str, Any]:
|
|
422
|
+
"""
|
|
423
|
+
Serializes a SpanEvent to a dictionary.
|
|
424
|
+
"""
|
|
425
|
+
return {k: (v.isoformat() if isinstance(v, datetime) else v) for k, v in asdict(event).items()}
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
JSON = OpenInferenceMimeTypeValues.JSON.value
|
|
429
|
+
TEXT = OpenInferenceMimeTypeValues.TEXT.value
|
|
430
|
+
|
|
431
|
+
LLM = OpenInferenceSpanKindValues.LLM.value
|
|
432
|
+
|
|
433
|
+
OPENINFERENCE_SPAN_KIND = SpanAttributes.OPENINFERENCE_SPAN_KIND
|
|
434
|
+
INPUT_MIME_TYPE = SpanAttributes.INPUT_MIME_TYPE
|
|
435
|
+
INPUT_VALUE = SpanAttributes.INPUT_VALUE
|
|
436
|
+
OUTPUT_MIME_TYPE = SpanAttributes.OUTPUT_MIME_TYPE
|
|
437
|
+
OUTPUT_VALUE = SpanAttributes.OUTPUT_VALUE
|
|
438
|
+
LLM_INPUT_MESSAGES = SpanAttributes.LLM_INPUT_MESSAGES
|
|
439
|
+
LLM_OUTPUT_MESSAGES = SpanAttributes.LLM_OUTPUT_MESSAGES
|
|
440
|
+
LLM_MODEL_NAME = SpanAttributes.LLM_MODEL_NAME
|
|
441
|
+
LLM_INVOCATION_PARAMETERS = SpanAttributes.LLM_INVOCATION_PARAMETERS
|
|
442
|
+
LLM_TOOLS = SpanAttributes.LLM_TOOLS
|
|
443
|
+
LLM_TOKEN_COUNT_PROMPT = SpanAttributes.LLM_TOKEN_COUNT_PROMPT
|
|
444
|
+
LLM_TOKEN_COUNT_COMPLETION = SpanAttributes.LLM_TOKEN_COUNT_COMPLETION
|
|
445
|
+
|
|
446
|
+
MESSAGE_CONTENT = MessageAttributes.MESSAGE_CONTENT
|
|
447
|
+
MESSAGE_ROLE = MessageAttributes.MESSAGE_ROLE
|
|
448
|
+
MESSAGE_TOOL_CALLS = MessageAttributes.MESSAGE_TOOL_CALLS
|
|
449
|
+
|
|
450
|
+
TOOL_CALL_ID = ToolCallAttributes.TOOL_CALL_ID
|
|
451
|
+
TOOL_CALL_FUNCTION_NAME = ToolCallAttributes.TOOL_CALL_FUNCTION_NAME
|
|
452
|
+
TOOL_CALL_FUNCTION_ARGUMENTS_JSON = ToolCallAttributes.TOOL_CALL_FUNCTION_ARGUMENTS_JSON
|
|
453
|
+
TOOL_CALL_ID = ToolCallAttributes.TOOL_CALL_ID
|
|
454
|
+
MESSAGE_TOOL_CALL_ID = MessageAttributes.MESSAGE_TOOL_CALL_ID
|
|
455
|
+
TOOL_JSON_SCHEMA = ToolAttributes.TOOL_JSON_SCHEMA
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from strawberry import UNSET
|
|
5
|
+
from strawberry.relay import GlobalID
|
|
6
|
+
from strawberry.scalars import JSON
|
|
7
|
+
|
|
8
|
+
from .DatasetExampleInput import DatasetExampleInput
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@strawberry.input
|
|
12
|
+
class AddExamplesToDatasetInput:
|
|
13
|
+
dataset_id: GlobalID
|
|
14
|
+
examples: list[DatasetExampleInput]
|
|
15
|
+
dataset_version_description: Optional[str] = UNSET
|
|
16
|
+
dataset_version_metadata: Optional[JSON] = UNSET
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from strawberry import UNSET
|
|
5
|
+
from strawberry.relay import GlobalID
|
|
6
|
+
from strawberry.scalars import JSON
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@strawberry.input
|
|
10
|
+
class AddSpansToDatasetInput:
|
|
11
|
+
dataset_id: GlobalID
|
|
12
|
+
span_ids: list[GlobalID]
|
|
13
|
+
dataset_version_description: Optional[str] = UNSET
|
|
14
|
+
dataset_version_metadata: Optional[JSON] = UNSET
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from strawberry import UNSET
|
|
5
|
+
from strawberry.relay.types import GlobalID
|
|
6
|
+
from strawberry.scalars import JSON
|
|
7
|
+
|
|
8
|
+
from phoenix.server.api.types.TemplateLanguage import TemplateLanguage
|
|
9
|
+
|
|
10
|
+
from .ChatCompletionMessageInput import ChatCompletionMessageInput
|
|
11
|
+
from .GenerativeModelInput import GenerativeModelInput
|
|
12
|
+
from .InvocationParameters import InvocationParameterInput
|
|
13
|
+
from .TemplateOptions import TemplateOptions
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@strawberry.input
|
|
17
|
+
class ChatCompletionInput:
|
|
18
|
+
messages: list[ChatCompletionMessageInput]
|
|
19
|
+
model: GenerativeModelInput
|
|
20
|
+
invocation_parameters: list[InvocationParameterInput] = strawberry.field(default_factory=list)
|
|
21
|
+
tools: Optional[list[JSON]] = UNSET
|
|
22
|
+
api_key: Optional[str] = strawberry.field(default=None)
|
|
23
|
+
template: Optional[TemplateOptions] = UNSET
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@strawberry.input
|
|
27
|
+
class ChatCompletionOverDatasetInput:
|
|
28
|
+
messages: list[ChatCompletionMessageInput]
|
|
29
|
+
model: GenerativeModelInput
|
|
30
|
+
invocation_parameters: list[InvocationParameterInput] = strawberry.field(default_factory=list)
|
|
31
|
+
tools: Optional[list[JSON]] = UNSET
|
|
32
|
+
api_key: Optional[str] = strawberry.field(default=None)
|
|
33
|
+
template_language: TemplateLanguage
|
|
34
|
+
dataset_id: GlobalID
|
|
35
|
+
dataset_version_id: Optional[GlobalID] = None
|
|
36
|
+
experiment_name: Optional[str] = None
|
|
37
|
+
experiment_description: Optional[str] = None
|
|
38
|
+
experiment_metadata: Optional[JSON] = strawberry.field(default_factory=dict)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from strawberry import UNSET
|
|
5
|
+
from strawberry.scalars import JSON
|
|
6
|
+
|
|
7
|
+
from phoenix.server.api.types.ChatCompletionMessageRole import ChatCompletionMessageRole
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@strawberry.input
|
|
11
|
+
class ChatCompletionMessageInput:
|
|
12
|
+
role: ChatCompletionMessageRole
|
|
13
|
+
content: JSON = strawberry.field(
|
|
14
|
+
default="",
|
|
15
|
+
description="The content of the message as JSON to support various kinds of text",
|
|
16
|
+
)
|
|
17
|
+
tool_calls: Optional[list[JSON]] = strawberry.field(
|
|
18
|
+
description="The tool calls that were made in the message",
|
|
19
|
+
default=UNSET,
|
|
20
|
+
)
|
|
21
|
+
tool_call_id: Optional[str] = strawberry.field(
|
|
22
|
+
description="The ID that corresponds to a prior tool call. Used to link a tool message to a pre-existing tool call.", # noqa: E501
|
|
23
|
+
default=UNSET,
|
|
24
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import strawberry
|
|
5
|
+
from strawberry import UNSET
|
|
6
|
+
from strawberry.relay import GlobalID
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@strawberry.input
|
|
10
|
+
class ClearProjectInput:
|
|
11
|
+
id: GlobalID
|
|
12
|
+
end_time: Optional[datetime] = strawberry.field(
|
|
13
|
+
default=UNSET,
|
|
14
|
+
description="The time up to which to purge data. Time is right-open /non-inclusive.",
|
|
15
|
+
)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import
|
|
1
|
+
from typing import Optional
|
|
2
2
|
|
|
3
3
|
import strawberry
|
|
4
4
|
from strawberry import ID, UNSET
|
|
@@ -6,5 +6,5 @@ from strawberry import ID, UNSET
|
|
|
6
6
|
|
|
7
7
|
@strawberry.input
|
|
8
8
|
class ClusterInput:
|
|
9
|
-
event_ids:
|
|
9
|
+
event_ids: list[ID]
|
|
10
10
|
id: Optional[ID] = UNSET
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
import strawberry
|
|
4
|
+
from strawberry import UNSET
|
|
5
|
+
from strawberry.scalars import JSON
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@strawberry.input
|
|
9
|
+
class CreateDatasetInput:
|
|
10
|
+
name: str
|
|
11
|
+
description: Optional[str] = UNSET
|
|
12
|
+
metadata: Optional[JSON] = UNSET
|
|
@@ -0,0 +1,18 @@
|
|
|
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.types.AnnotatorKind import AnnotatorKind
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@strawberry.input
|
|
11
|
+
class CreateSpanAnnotationInput:
|
|
12
|
+
span_id: GlobalID
|
|
13
|
+
name: str
|
|
14
|
+
annotator_kind: AnnotatorKind
|
|
15
|
+
label: Optional[str] = None
|
|
16
|
+
score: Optional[float] = None
|
|
17
|
+
explanation: Optional[str] = None
|
|
18
|
+
metadata: JSON = strawberry.field(default_factory=dict)
|