arize-phoenix 3.16.0__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.

Files changed (338) hide show
  1. arize_phoenix-7.7.0.dist-info/METADATA +261 -0
  2. arize_phoenix-7.7.0.dist-info/RECORD +345 -0
  3. {arize_phoenix-3.16.0.dist-info → arize_phoenix-7.7.0.dist-info}/WHEEL +1 -1
  4. arize_phoenix-7.7.0.dist-info/entry_points.txt +3 -0
  5. phoenix/__init__.py +86 -14
  6. phoenix/auth.py +309 -0
  7. phoenix/config.py +675 -45
  8. phoenix/core/model.py +32 -30
  9. phoenix/core/model_schema.py +102 -109
  10. phoenix/core/model_schema_adapter.py +48 -45
  11. phoenix/datetime_utils.py +24 -3
  12. phoenix/db/README.md +54 -0
  13. phoenix/db/__init__.py +4 -0
  14. phoenix/db/alembic.ini +85 -0
  15. phoenix/db/bulk_inserter.py +294 -0
  16. phoenix/db/engines.py +208 -0
  17. phoenix/db/enums.py +20 -0
  18. phoenix/db/facilitator.py +113 -0
  19. phoenix/db/helpers.py +159 -0
  20. phoenix/db/insertion/constants.py +2 -0
  21. phoenix/db/insertion/dataset.py +227 -0
  22. phoenix/db/insertion/document_annotation.py +171 -0
  23. phoenix/db/insertion/evaluation.py +191 -0
  24. phoenix/db/insertion/helpers.py +98 -0
  25. phoenix/db/insertion/span.py +193 -0
  26. phoenix/db/insertion/span_annotation.py +158 -0
  27. phoenix/db/insertion/trace_annotation.py +158 -0
  28. phoenix/db/insertion/types.py +256 -0
  29. phoenix/db/migrate.py +86 -0
  30. phoenix/db/migrations/data_migration_scripts/populate_project_sessions.py +199 -0
  31. phoenix/db/migrations/env.py +114 -0
  32. phoenix/db/migrations/script.py.mako +26 -0
  33. phoenix/db/migrations/versions/10460e46d750_datasets.py +317 -0
  34. phoenix/db/migrations/versions/3be8647b87d8_add_token_columns_to_spans_table.py +126 -0
  35. phoenix/db/migrations/versions/4ded9e43755f_create_project_sessions_table.py +66 -0
  36. phoenix/db/migrations/versions/cd164e83824f_users_and_tokens.py +157 -0
  37. phoenix/db/migrations/versions/cf03bd6bae1d_init.py +280 -0
  38. phoenix/db/models.py +807 -0
  39. phoenix/exceptions.py +5 -1
  40. phoenix/experiments/__init__.py +6 -0
  41. phoenix/experiments/evaluators/__init__.py +29 -0
  42. phoenix/experiments/evaluators/base.py +158 -0
  43. phoenix/experiments/evaluators/code_evaluators.py +184 -0
  44. phoenix/experiments/evaluators/llm_evaluators.py +473 -0
  45. phoenix/experiments/evaluators/utils.py +236 -0
  46. phoenix/experiments/functions.py +772 -0
  47. phoenix/experiments/tracing.py +86 -0
  48. phoenix/experiments/types.py +726 -0
  49. phoenix/experiments/utils.py +25 -0
  50. phoenix/inferences/__init__.py +0 -0
  51. phoenix/{datasets → inferences}/errors.py +6 -5
  52. phoenix/{datasets → inferences}/fixtures.py +49 -42
  53. phoenix/{datasets/dataset.py → inferences/inferences.py} +121 -105
  54. phoenix/{datasets → inferences}/schema.py +11 -11
  55. phoenix/{datasets → inferences}/validation.py +13 -14
  56. phoenix/logging/__init__.py +3 -0
  57. phoenix/logging/_config.py +90 -0
  58. phoenix/logging/_filter.py +6 -0
  59. phoenix/logging/_formatter.py +69 -0
  60. phoenix/metrics/__init__.py +5 -4
  61. phoenix/metrics/binning.py +4 -3
  62. phoenix/metrics/metrics.py +2 -1
  63. phoenix/metrics/mixins.py +7 -6
  64. phoenix/metrics/retrieval_metrics.py +2 -1
  65. phoenix/metrics/timeseries.py +5 -4
  66. phoenix/metrics/wrappers.py +9 -3
  67. phoenix/pointcloud/clustering.py +5 -5
  68. phoenix/pointcloud/pointcloud.py +7 -5
  69. phoenix/pointcloud/projectors.py +5 -6
  70. phoenix/pointcloud/umap_parameters.py +53 -52
  71. phoenix/server/api/README.md +28 -0
  72. phoenix/server/api/auth.py +44 -0
  73. phoenix/server/api/context.py +152 -9
  74. phoenix/server/api/dataloaders/__init__.py +91 -0
  75. phoenix/server/api/dataloaders/annotation_summaries.py +139 -0
  76. phoenix/server/api/dataloaders/average_experiment_run_latency.py +54 -0
  77. phoenix/server/api/dataloaders/cache/__init__.py +3 -0
  78. phoenix/server/api/dataloaders/cache/two_tier_cache.py +68 -0
  79. phoenix/server/api/dataloaders/dataset_example_revisions.py +131 -0
  80. phoenix/server/api/dataloaders/dataset_example_spans.py +38 -0
  81. phoenix/server/api/dataloaders/document_evaluation_summaries.py +144 -0
  82. phoenix/server/api/dataloaders/document_evaluations.py +31 -0
  83. phoenix/server/api/dataloaders/document_retrieval_metrics.py +89 -0
  84. phoenix/server/api/dataloaders/experiment_annotation_summaries.py +79 -0
  85. phoenix/server/api/dataloaders/experiment_error_rates.py +58 -0
  86. phoenix/server/api/dataloaders/experiment_run_annotations.py +36 -0
  87. phoenix/server/api/dataloaders/experiment_run_counts.py +49 -0
  88. phoenix/server/api/dataloaders/experiment_sequence_number.py +44 -0
  89. phoenix/server/api/dataloaders/latency_ms_quantile.py +188 -0
  90. phoenix/server/api/dataloaders/min_start_or_max_end_times.py +85 -0
  91. phoenix/server/api/dataloaders/project_by_name.py +31 -0
  92. phoenix/server/api/dataloaders/record_counts.py +116 -0
  93. phoenix/server/api/dataloaders/session_io.py +79 -0
  94. phoenix/server/api/dataloaders/session_num_traces.py +30 -0
  95. phoenix/server/api/dataloaders/session_num_traces_with_error.py +32 -0
  96. phoenix/server/api/dataloaders/session_token_usages.py +41 -0
  97. phoenix/server/api/dataloaders/session_trace_latency_ms_quantile.py +55 -0
  98. phoenix/server/api/dataloaders/span_annotations.py +26 -0
  99. phoenix/server/api/dataloaders/span_dataset_examples.py +31 -0
  100. phoenix/server/api/dataloaders/span_descendants.py +57 -0
  101. phoenix/server/api/dataloaders/span_projects.py +33 -0
  102. phoenix/server/api/dataloaders/token_counts.py +124 -0
  103. phoenix/server/api/dataloaders/trace_by_trace_ids.py +25 -0
  104. phoenix/server/api/dataloaders/trace_root_spans.py +32 -0
  105. phoenix/server/api/dataloaders/user_roles.py +30 -0
  106. phoenix/server/api/dataloaders/users.py +33 -0
  107. phoenix/server/api/exceptions.py +48 -0
  108. phoenix/server/api/helpers/__init__.py +12 -0
  109. phoenix/server/api/helpers/dataset_helpers.py +217 -0
  110. phoenix/server/api/helpers/experiment_run_filters.py +763 -0
  111. phoenix/server/api/helpers/playground_clients.py +948 -0
  112. phoenix/server/api/helpers/playground_registry.py +70 -0
  113. phoenix/server/api/helpers/playground_spans.py +455 -0
  114. phoenix/server/api/input_types/AddExamplesToDatasetInput.py +16 -0
  115. phoenix/server/api/input_types/AddSpansToDatasetInput.py +14 -0
  116. phoenix/server/api/input_types/ChatCompletionInput.py +38 -0
  117. phoenix/server/api/input_types/ChatCompletionMessageInput.py +24 -0
  118. phoenix/server/api/input_types/ClearProjectInput.py +15 -0
  119. phoenix/server/api/input_types/ClusterInput.py +2 -2
  120. phoenix/server/api/input_types/CreateDatasetInput.py +12 -0
  121. phoenix/server/api/input_types/CreateSpanAnnotationInput.py +18 -0
  122. phoenix/server/api/input_types/CreateTraceAnnotationInput.py +18 -0
  123. phoenix/server/api/input_types/DataQualityMetricInput.py +5 -2
  124. phoenix/server/api/input_types/DatasetExampleInput.py +14 -0
  125. phoenix/server/api/input_types/DatasetSort.py +17 -0
  126. phoenix/server/api/input_types/DatasetVersionSort.py +16 -0
  127. phoenix/server/api/input_types/DeleteAnnotationsInput.py +7 -0
  128. phoenix/server/api/input_types/DeleteDatasetExamplesInput.py +13 -0
  129. phoenix/server/api/input_types/DeleteDatasetInput.py +7 -0
  130. phoenix/server/api/input_types/DeleteExperimentsInput.py +7 -0
  131. phoenix/server/api/input_types/DimensionFilter.py +4 -4
  132. phoenix/server/api/input_types/GenerativeModelInput.py +17 -0
  133. phoenix/server/api/input_types/Granularity.py +1 -1
  134. phoenix/server/api/input_types/InvocationParameters.py +162 -0
  135. phoenix/server/api/input_types/PatchAnnotationInput.py +19 -0
  136. phoenix/server/api/input_types/PatchDatasetExamplesInput.py +35 -0
  137. phoenix/server/api/input_types/PatchDatasetInput.py +14 -0
  138. phoenix/server/api/input_types/PerformanceMetricInput.py +5 -2
  139. phoenix/server/api/input_types/ProjectSessionSort.py +29 -0
  140. phoenix/server/api/input_types/SpanAnnotationSort.py +17 -0
  141. phoenix/server/api/input_types/SpanSort.py +134 -69
  142. phoenix/server/api/input_types/TemplateOptions.py +10 -0
  143. phoenix/server/api/input_types/TraceAnnotationSort.py +17 -0
  144. phoenix/server/api/input_types/UserRoleInput.py +9 -0
  145. phoenix/server/api/mutations/__init__.py +28 -0
  146. phoenix/server/api/mutations/api_key_mutations.py +167 -0
  147. phoenix/server/api/mutations/chat_mutations.py +593 -0
  148. phoenix/server/api/mutations/dataset_mutations.py +591 -0
  149. phoenix/server/api/mutations/experiment_mutations.py +75 -0
  150. phoenix/server/api/{types/ExportEventsMutation.py → mutations/export_events_mutations.py} +21 -18
  151. phoenix/server/api/mutations/project_mutations.py +57 -0
  152. phoenix/server/api/mutations/span_annotations_mutations.py +128 -0
  153. phoenix/server/api/mutations/trace_annotations_mutations.py +127 -0
  154. phoenix/server/api/mutations/user_mutations.py +329 -0
  155. phoenix/server/api/openapi/__init__.py +0 -0
  156. phoenix/server/api/openapi/main.py +17 -0
  157. phoenix/server/api/openapi/schema.py +16 -0
  158. phoenix/server/api/queries.py +738 -0
  159. phoenix/server/api/routers/__init__.py +11 -0
  160. phoenix/server/api/routers/auth.py +284 -0
  161. phoenix/server/api/routers/embeddings.py +26 -0
  162. phoenix/server/api/routers/oauth2.py +488 -0
  163. phoenix/server/api/routers/v1/__init__.py +64 -0
  164. phoenix/server/api/routers/v1/datasets.py +1017 -0
  165. phoenix/server/api/routers/v1/evaluations.py +362 -0
  166. phoenix/server/api/routers/v1/experiment_evaluations.py +115 -0
  167. phoenix/server/api/routers/v1/experiment_runs.py +167 -0
  168. phoenix/server/api/routers/v1/experiments.py +308 -0
  169. phoenix/server/api/routers/v1/pydantic_compat.py +78 -0
  170. phoenix/server/api/routers/v1/spans.py +267 -0
  171. phoenix/server/api/routers/v1/traces.py +208 -0
  172. phoenix/server/api/routers/v1/utils.py +95 -0
  173. phoenix/server/api/schema.py +44 -247
  174. phoenix/server/api/subscriptions.py +597 -0
  175. phoenix/server/api/types/Annotation.py +21 -0
  176. phoenix/server/api/types/AnnotationSummary.py +55 -0
  177. phoenix/server/api/types/AnnotatorKind.py +16 -0
  178. phoenix/server/api/types/ApiKey.py +27 -0
  179. phoenix/server/api/types/AuthMethod.py +9 -0
  180. phoenix/server/api/types/ChatCompletionMessageRole.py +11 -0
  181. phoenix/server/api/types/ChatCompletionSubscriptionPayload.py +46 -0
  182. phoenix/server/api/types/Cluster.py +25 -24
  183. phoenix/server/api/types/CreateDatasetPayload.py +8 -0
  184. phoenix/server/api/types/DataQualityMetric.py +31 -13
  185. phoenix/server/api/types/Dataset.py +288 -63
  186. phoenix/server/api/types/DatasetExample.py +85 -0
  187. phoenix/server/api/types/DatasetExampleRevision.py +34 -0
  188. phoenix/server/api/types/DatasetVersion.py +14 -0
  189. phoenix/server/api/types/Dimension.py +32 -31
  190. phoenix/server/api/types/DocumentEvaluationSummary.py +9 -8
  191. phoenix/server/api/types/EmbeddingDimension.py +56 -49
  192. phoenix/server/api/types/Evaluation.py +25 -31
  193. phoenix/server/api/types/EvaluationSummary.py +30 -50
  194. phoenix/server/api/types/Event.py +20 -20
  195. phoenix/server/api/types/ExampleRevisionInterface.py +14 -0
  196. phoenix/server/api/types/Experiment.py +152 -0
  197. phoenix/server/api/types/ExperimentAnnotationSummary.py +13 -0
  198. phoenix/server/api/types/ExperimentComparison.py +17 -0
  199. phoenix/server/api/types/ExperimentRun.py +119 -0
  200. phoenix/server/api/types/ExperimentRunAnnotation.py +56 -0
  201. phoenix/server/api/types/GenerativeModel.py +9 -0
  202. phoenix/server/api/types/GenerativeProvider.py +85 -0
  203. phoenix/server/api/types/Inferences.py +80 -0
  204. phoenix/server/api/types/InferencesRole.py +23 -0
  205. phoenix/server/api/types/LabelFraction.py +7 -0
  206. phoenix/server/api/types/MimeType.py +2 -2
  207. phoenix/server/api/types/Model.py +54 -54
  208. phoenix/server/api/types/PerformanceMetric.py +8 -5
  209. phoenix/server/api/types/Project.py +407 -142
  210. phoenix/server/api/types/ProjectSession.py +139 -0
  211. phoenix/server/api/types/Segments.py +4 -4
  212. phoenix/server/api/types/Span.py +221 -176
  213. phoenix/server/api/types/SpanAnnotation.py +43 -0
  214. phoenix/server/api/types/SpanIOValue.py +15 -0
  215. phoenix/server/api/types/SystemApiKey.py +9 -0
  216. phoenix/server/api/types/TemplateLanguage.py +10 -0
  217. phoenix/server/api/types/TimeSeries.py +19 -15
  218. phoenix/server/api/types/TokenUsage.py +11 -0
  219. phoenix/server/api/types/Trace.py +154 -0
  220. phoenix/server/api/types/TraceAnnotation.py +45 -0
  221. phoenix/server/api/types/UMAPPoints.py +7 -7
  222. phoenix/server/api/types/User.py +60 -0
  223. phoenix/server/api/types/UserApiKey.py +45 -0
  224. phoenix/server/api/types/UserRole.py +15 -0
  225. phoenix/server/api/types/node.py +13 -107
  226. phoenix/server/api/types/pagination.py +156 -57
  227. phoenix/server/api/utils.py +34 -0
  228. phoenix/server/app.py +864 -115
  229. phoenix/server/bearer_auth.py +163 -0
  230. phoenix/server/dml_event.py +136 -0
  231. phoenix/server/dml_event_handler.py +256 -0
  232. phoenix/server/email/__init__.py +0 -0
  233. phoenix/server/email/sender.py +97 -0
  234. phoenix/server/email/templates/__init__.py +0 -0
  235. phoenix/server/email/templates/password_reset.html +19 -0
  236. phoenix/server/email/types.py +11 -0
  237. phoenix/server/grpc_server.py +102 -0
  238. phoenix/server/jwt_store.py +505 -0
  239. phoenix/server/main.py +305 -116
  240. phoenix/server/oauth2.py +52 -0
  241. phoenix/server/openapi/__init__.py +0 -0
  242. phoenix/server/prometheus.py +111 -0
  243. phoenix/server/rate_limiters.py +188 -0
  244. phoenix/server/static/.vite/manifest.json +87 -0
  245. phoenix/server/static/assets/components-Cy9nwIvF.js +2125 -0
  246. phoenix/server/static/assets/index-BKvHIxkk.js +113 -0
  247. phoenix/server/static/assets/pages-CUi2xCVQ.js +4449 -0
  248. phoenix/server/static/assets/vendor-DvC8cT4X.js +894 -0
  249. phoenix/server/static/assets/vendor-DxkFTwjz.css +1 -0
  250. phoenix/server/static/assets/vendor-arizeai-Do1793cv.js +662 -0
  251. phoenix/server/static/assets/vendor-codemirror-BzwZPyJM.js +24 -0
  252. phoenix/server/static/assets/vendor-recharts-_Jb7JjhG.js +59 -0
  253. phoenix/server/static/assets/vendor-shiki-Cl9QBraO.js +5 -0
  254. phoenix/server/static/assets/vendor-three-DwGkEfCM.js +2998 -0
  255. phoenix/server/telemetry.py +68 -0
  256. phoenix/server/templates/index.html +82 -23
  257. phoenix/server/thread_server.py +3 -3
  258. phoenix/server/types.py +275 -0
  259. phoenix/services.py +27 -18
  260. phoenix/session/client.py +743 -68
  261. phoenix/session/data_extractor.py +31 -7
  262. phoenix/session/evaluation.py +3 -9
  263. phoenix/session/session.py +263 -219
  264. phoenix/settings.py +22 -0
  265. phoenix/trace/__init__.py +2 -22
  266. phoenix/trace/attributes.py +338 -0
  267. phoenix/trace/dsl/README.md +116 -0
  268. phoenix/trace/dsl/filter.py +663 -213
  269. phoenix/trace/dsl/helpers.py +73 -21
  270. phoenix/trace/dsl/query.py +574 -201
  271. phoenix/trace/exporter.py +24 -19
  272. phoenix/trace/fixtures.py +368 -32
  273. phoenix/trace/otel.py +71 -219
  274. phoenix/trace/projects.py +3 -2
  275. phoenix/trace/schemas.py +33 -11
  276. phoenix/trace/span_evaluations.py +21 -16
  277. phoenix/trace/span_json_decoder.py +6 -4
  278. phoenix/trace/span_json_encoder.py +2 -2
  279. phoenix/trace/trace_dataset.py +47 -32
  280. phoenix/trace/utils.py +21 -4
  281. phoenix/utilities/__init__.py +0 -26
  282. phoenix/utilities/client.py +132 -0
  283. phoenix/utilities/deprecation.py +31 -0
  284. phoenix/utilities/error_handling.py +3 -2
  285. phoenix/utilities/json.py +109 -0
  286. phoenix/utilities/logging.py +8 -0
  287. phoenix/utilities/project.py +2 -2
  288. phoenix/utilities/re.py +49 -0
  289. phoenix/utilities/span_store.py +0 -23
  290. phoenix/utilities/template_formatters.py +99 -0
  291. phoenix/version.py +1 -1
  292. arize_phoenix-3.16.0.dist-info/METADATA +0 -495
  293. arize_phoenix-3.16.0.dist-info/RECORD +0 -178
  294. phoenix/core/project.py +0 -617
  295. phoenix/core/traces.py +0 -100
  296. phoenix/experimental/evals/__init__.py +0 -73
  297. phoenix/experimental/evals/evaluators.py +0 -413
  298. phoenix/experimental/evals/functions/__init__.py +0 -4
  299. phoenix/experimental/evals/functions/classify.py +0 -453
  300. phoenix/experimental/evals/functions/executor.py +0 -353
  301. phoenix/experimental/evals/functions/generate.py +0 -138
  302. phoenix/experimental/evals/functions/processing.py +0 -76
  303. phoenix/experimental/evals/models/__init__.py +0 -14
  304. phoenix/experimental/evals/models/anthropic.py +0 -175
  305. phoenix/experimental/evals/models/base.py +0 -170
  306. phoenix/experimental/evals/models/bedrock.py +0 -221
  307. phoenix/experimental/evals/models/litellm.py +0 -134
  308. phoenix/experimental/evals/models/openai.py +0 -448
  309. phoenix/experimental/evals/models/rate_limiters.py +0 -246
  310. phoenix/experimental/evals/models/vertex.py +0 -173
  311. phoenix/experimental/evals/models/vertexai.py +0 -186
  312. phoenix/experimental/evals/retrievals.py +0 -96
  313. phoenix/experimental/evals/templates/__init__.py +0 -50
  314. phoenix/experimental/evals/templates/default_templates.py +0 -472
  315. phoenix/experimental/evals/templates/template.py +0 -195
  316. phoenix/experimental/evals/utils/__init__.py +0 -172
  317. phoenix/experimental/evals/utils/threads.py +0 -27
  318. phoenix/server/api/helpers.py +0 -11
  319. phoenix/server/api/routers/evaluation_handler.py +0 -109
  320. phoenix/server/api/routers/span_handler.py +0 -70
  321. phoenix/server/api/routers/trace_handler.py +0 -60
  322. phoenix/server/api/types/DatasetRole.py +0 -23
  323. phoenix/server/static/index.css +0 -6
  324. phoenix/server/static/index.js +0 -7447
  325. phoenix/storage/span_store/__init__.py +0 -23
  326. phoenix/storage/span_store/text_file.py +0 -85
  327. phoenix/trace/dsl/missing.py +0 -60
  328. phoenix/trace/langchain/__init__.py +0 -3
  329. phoenix/trace/langchain/instrumentor.py +0 -35
  330. phoenix/trace/llama_index/__init__.py +0 -3
  331. phoenix/trace/llama_index/callback.py +0 -102
  332. phoenix/trace/openai/__init__.py +0 -3
  333. phoenix/trace/openai/instrumentor.py +0 -30
  334. {arize_phoenix-3.16.0.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/IP_NOTICE +0 -0
  335. {arize_phoenix-3.16.0.dist-info → arize_phoenix-7.7.0.dist-info}/licenses/LICENSE +0 -0
  336. /phoenix/{datasets → db/insertion}/__init__.py +0 -0
  337. /phoenix/{experimental → db/migrations}/__init__.py +0 -0
  338. /phoenix/{storage → db/migrations/data_migration_scripts}/__init__.py +0 -0
@@ -1,36 +1,41 @@
1
1
  import json
2
- from collections import defaultdict
2
+ from collections.abc import Mapping, Sized
3
3
  from datetime import datetime
4
4
  from enum import Enum
5
- from typing import Any, DefaultDict, Dict, List, Mapping, Optional, Sized, cast
5
+ from typing import TYPE_CHECKING, Any, Optional, cast
6
6
 
7
7
  import numpy as np
8
8
  import strawberry
9
- from openinference.semconv.trace import EmbeddingAttributes, SpanAttributes
9
+ from openinference.semconv.trace import SpanAttributes
10
10
  from strawberry import ID, UNSET
11
+ from strawberry.relay import Node, NodeID
11
12
  from strawberry.types import Info
13
+ from typing_extensions import Annotated
12
14
 
13
15
  import phoenix.trace.schemas as trace_schema
14
- from phoenix.config import DEFAULT_PROJECT_NAME
15
- from phoenix.core.project import Project, WrappedSpan
16
- from phoenix.metrics.retrieval_metrics import RetrievalMetrics
16
+ from phoenix.db import models
17
17
  from phoenix.server.api.context import Context
18
+ from phoenix.server.api.helpers.dataset_helpers import (
19
+ get_dataset_example_input,
20
+ get_dataset_example_output,
21
+ )
22
+ from phoenix.server.api.input_types.InvocationParameters import InvocationParameter
23
+ from phoenix.server.api.input_types.SpanAnnotationSort import (
24
+ SpanAnnotationColumn,
25
+ SpanAnnotationSort,
26
+ )
18
27
  from phoenix.server.api.types.DocumentRetrievalMetrics import DocumentRetrievalMetrics
19
- from phoenix.server.api.types.Evaluation import DocumentEvaluation, SpanEvaluation
28
+ from phoenix.server.api.types.Evaluation import DocumentEvaluation
29
+ from phoenix.server.api.types.ExampleRevisionInterface import ExampleRevision
30
+ from phoenix.server.api.types.GenerativeProvider import GenerativeProvider
20
31
  from phoenix.server.api.types.MimeType import MimeType
21
- from phoenix.trace.schemas import ComputedAttributes, SpanID
32
+ from phoenix.server.api.types.SortDir import SortDir
33
+ from phoenix.server.api.types.SpanAnnotation import SpanAnnotation, to_gql_span_annotation
34
+ from phoenix.server.api.types.SpanIOValue import SpanIOValue
35
+ from phoenix.trace.attributes import get_attribute_value
22
36
 
23
- EMBEDDING_EMBEDDINGS = SpanAttributes.EMBEDDING_EMBEDDINGS
24
- EMBEDDING_VECTOR = EmbeddingAttributes.EMBEDDING_VECTOR
25
- INPUT_MIME_TYPE = SpanAttributes.INPUT_MIME_TYPE
26
- INPUT_VALUE = SpanAttributes.INPUT_VALUE
27
- LLM_TOKEN_COUNT_COMPLETION = SpanAttributes.LLM_TOKEN_COUNT_COMPLETION
28
- LLM_TOKEN_COUNT_PROMPT = SpanAttributes.LLM_TOKEN_COUNT_PROMPT
29
- LLM_TOKEN_COUNT_TOTAL = SpanAttributes.LLM_TOKEN_COUNT_TOTAL
30
- METADATA = SpanAttributes.METADATA
31
- OUTPUT_MIME_TYPE = SpanAttributes.OUTPUT_MIME_TYPE
32
- OUTPUT_VALUE = SpanAttributes.OUTPUT_VALUE
33
- RETRIEVAL_DOCUMENTS = SpanAttributes.RETRIEVAL_DOCUMENTS
37
+ if TYPE_CHECKING:
38
+ from phoenix.server.api.types.Project import Project
34
39
 
35
40
 
36
41
  @strawberry.enum
@@ -41,18 +46,22 @@ class SpanKind(Enum):
41
46
  NB: this is actively under construction
42
47
  """
43
48
 
44
- chain = trace_schema.SpanKind.CHAIN
45
- tool = trace_schema.SpanKind.TOOL
46
- llm = trace_schema.SpanKind.LLM
47
- retriever = trace_schema.SpanKind.RETRIEVER
48
- embedding = trace_schema.SpanKind.EMBEDDING
49
- agent = trace_schema.SpanKind.AGENT
50
- reranker = trace_schema.SpanKind.RERANKER
51
- unknown = trace_schema.SpanKind.UNKNOWN
49
+ chain = "CHAIN"
50
+ tool = "TOOL"
51
+ llm = "LLM"
52
+ retriever = "RETRIEVER"
53
+ embedding = "EMBEDDING"
54
+ agent = "AGENT"
55
+ reranker = "RERANKER"
56
+ evaluator = "EVALUATOR"
57
+ guardrail = "GUARDRAIL"
58
+ unknown = "UNKNOWN"
52
59
 
53
60
  @classmethod
54
61
  def _missing_(cls, v: Any) -> Optional["SpanKind"]:
55
- return None if v else cls.unknown
62
+ if v and isinstance(v, str) and v.isascii() and not v.isupper():
63
+ return cls(v.upper())
64
+ return cls.unknown
56
65
 
57
66
 
58
67
  @strawberry.type
@@ -61,17 +70,11 @@ class SpanContext:
61
70
  span_id: ID
62
71
 
63
72
 
64
- @strawberry.type
65
- class SpanIOValue:
66
- mime_type: MimeType
67
- value: str
68
-
69
-
70
73
  @strawberry.enum
71
74
  class SpanStatusCode(Enum):
72
- OK = trace_schema.SpanStatusCode.OK
73
- ERROR = trace_schema.SpanStatusCode.ERROR
74
- UNSET = trace_schema.SpanStatusCode.UNSET
75
+ OK = "OK"
76
+ ERROR = "ERROR"
77
+ UNSET = "UNSET"
75
78
 
76
79
  @classmethod
77
80
  def _missing_(cls, v: Any) -> Optional["SpanStatusCode"]:
@@ -85,19 +88,24 @@ class SpanEvent:
85
88
  timestamp: datetime
86
89
 
87
90
  @staticmethod
88
- def from_event(
89
- event: trace_schema.SpanEvent,
91
+ def from_dict(
92
+ event: Mapping[str, Any],
90
93
  ) -> "SpanEvent":
91
94
  return SpanEvent(
92
- name=event.name,
93
- message=cast(str, event.attributes.get(trace_schema.EXCEPTION_MESSAGE) or ""),
94
- timestamp=event.timestamp,
95
+ name=event["name"],
96
+ message=cast(str, event["attributes"].get(trace_schema.EXCEPTION_MESSAGE) or ""),
97
+ timestamp=datetime.fromisoformat(event["timestamp"]),
95
98
  )
96
99
 
97
100
 
98
101
  @strawberry.type
99
- class Span:
100
- project: strawberry.Private[Project]
102
+ class SpanAsExampleRevision(ExampleRevision): ...
103
+
104
+
105
+ @strawberry.type
106
+ class Span(Node):
107
+ id_attr: NodeID[int]
108
+ db_span: strawberry.Private[models.Span]
101
109
  name: str
102
110
  status_code: SpanStatusCode
103
111
  status_message: str
@@ -121,7 +129,7 @@ class Span:
121
129
  token_count_completion: Optional[int]
122
130
  input: Optional[SpanIOValue]
123
131
  output: Optional[SpanIOValue]
124
- events: List[SpanEvent]
132
+ events: list[SpanEvent]
125
133
  cumulative_token_count_total: Optional[int] = strawberry.field(
126
134
  description="Cumulative (prompt plus completion) token count from "
127
135
  "self and all descendant spans (children, grandchildren, etc.)",
@@ -140,23 +148,27 @@ class Span:
140
148
  )
141
149
 
142
150
  @strawberry.field(
143
- description="Evaluations associated with the span, e.g. if the span is "
144
- "an LLM, an evaluation may assess the helpfulness of its response with "
145
- "respect to its input."
151
+ description=(
152
+ "Annotations associated with the span. This encompasses both "
153
+ "LLM and human annotations."
154
+ )
146
155
  ) # type: ignore
147
- def span_evaluations(
156
+ async def span_annotations(
148
157
  self,
149
158
  info: Info[Context, None],
150
- ) -> List[SpanEvaluation]:
151
- if not (traces := info.context.traces) or not (
152
- project := traces.get_project(DEFAULT_PROJECT_NAME)
153
- ):
154
- return []
155
- span_id = SpanID(str(self.context.span_id))
156
- return [
157
- SpanEvaluation.from_pb_evaluation(evaluation)
158
- for evaluation in project.get_evaluations_by_span_id(span_id)
159
- ]
159
+ sort: Optional[SpanAnnotationSort] = UNSET,
160
+ ) -> list[SpanAnnotation]:
161
+ span_id = self.id_attr
162
+ annotations = await info.context.data_loaders.span_annotations.load(span_id)
163
+ sort_key = SpanAnnotationColumn.name.value
164
+ sort_descending = False
165
+ if sort:
166
+ sort_key = sort.col.value
167
+ sort_descending = sort.dir is SortDir.desc
168
+ annotations.sort(
169
+ key=lambda annotation: getattr(annotation, sort_key), reverse=sort_descending
170
+ )
171
+ return [to_gql_span_annotation(annotation) for annotation in annotations]
160
172
 
161
173
  @strawberry.field(
162
174
  description="Evaluations of the documents associated with the span, e.g. "
@@ -166,76 +178,131 @@ class Span:
166
178
  "a list, and each evaluation is identified by its document's (zero-based) "
167
179
  "index in that list."
168
180
  ) # type: ignore
169
- def document_evaluations(
170
- self,
171
- info: Info[Context, None],
172
- ) -> List[DocumentEvaluation]:
173
- if not (traces := info.context.traces) or not (
174
- project := traces.get_project(DEFAULT_PROJECT_NAME)
175
- ):
176
- return []
177
- span_id = SpanID(str(self.context.span_id))
178
- return [
179
- DocumentEvaluation.from_pb_evaluation(evaluation)
180
- for evaluation in project.get_document_evaluations_by_span_id(span_id)
181
- ]
181
+ async def document_evaluations(self, info: Info[Context, None]) -> list[DocumentEvaluation]:
182
+ return await info.context.data_loaders.document_evaluations.load(self.id_attr)
182
183
 
183
184
  @strawberry.field(
184
185
  description="Retrieval metrics: NDCG@K, Precision@K, Reciprocal Rank, etc.",
185
186
  ) # type: ignore
186
- def document_retrieval_metrics(
187
+ async def document_retrieval_metrics(
187
188
  self,
188
189
  info: Info[Context, None],
189
190
  evaluation_name: Optional[str] = UNSET,
190
- ) -> List[DocumentRetrievalMetrics]:
191
+ ) -> list[DocumentRetrievalMetrics]:
191
192
  if not self.num_documents:
192
193
  return []
193
- span_id = SpanID(str(self.context.span_id))
194
- all_document_evaluation_names = self.project.get_document_evaluation_names(span_id)
195
- if not all_document_evaluation_names:
196
- return []
197
- if evaluation_name is UNSET:
198
- evaluation_names = all_document_evaluation_names
199
- elif evaluation_name not in all_document_evaluation_names:
200
- return []
201
- else:
202
- evaluation_names = [evaluation_name]
203
- retrieval_metrics = []
204
- for name in evaluation_names:
205
- evaluation_scores = self.project.get_document_evaluation_scores(
206
- span_id=span_id,
207
- evaluation_name=name,
208
- num_documents=self.num_documents,
209
- )
210
- retrieval_metrics.append(
211
- DocumentRetrievalMetrics(
212
- evaluation_name=name,
213
- metrics=RetrievalMetrics(evaluation_scores),
214
- )
215
- )
216
- return retrieval_metrics
194
+ return await info.context.data_loaders.document_retrieval_metrics.load(
195
+ (self.id_attr, evaluation_name or None, self.num_documents),
196
+ )
217
197
 
218
198
  @strawberry.field(
219
199
  description="All descendant spans (children, grandchildren, etc.)",
220
200
  ) # type: ignore
221
- def descendants(
201
+ async def descendants(
202
+ self,
203
+ info: Info[Context, None],
204
+ ) -> list["Span"]:
205
+ span_id = str(self.context.span_id)
206
+ spans = await info.context.data_loaders.span_descendants.load(span_id)
207
+ return [to_gql_span(span) for span in spans]
208
+
209
+ @strawberry.field(
210
+ description="The span's attributes translated into an example revision for a dataset",
211
+ ) # type: ignore
212
+ async def as_example_revision(self, info: Info[Context, None]) -> SpanAsExampleRevision:
213
+ span = self.db_span
214
+
215
+ # Fetch annotations associated with this span
216
+ span_annotations = await self.span_annotations(info)
217
+ annotations = dict()
218
+ for annotation in span_annotations:
219
+ annotations[annotation.name] = {
220
+ "label": annotation.label,
221
+ "score": annotation.score,
222
+ "explanation": annotation.explanation,
223
+ "metadata": annotation.metadata,
224
+ "annotator_kind": annotation.annotator_kind.value,
225
+ }
226
+ # Merge annotations into the metadata
227
+ metadata = {
228
+ "span_kind": span.span_kind,
229
+ **({"annotations": annotations} if annotations else {}),
230
+ }
231
+
232
+ return SpanAsExampleRevision(
233
+ input=get_dataset_example_input(span),
234
+ output=get_dataset_example_output(span),
235
+ metadata=metadata,
236
+ )
237
+
238
+ @strawberry.field(description="The project that this span belongs to.") # type: ignore
239
+ async def project(
222
240
  self,
223
241
  info: Info[Context, None],
224
- ) -> List["Span"]:
242
+ ) -> Annotated[
243
+ "Project", strawberry.lazy("phoenix.server.api.types.Project")
244
+ ]: # use lazy types to avoid circular import: https://strawberry.rocks/docs/types/lazy
245
+ from phoenix.server.api.types.Project import to_gql_project
246
+
247
+ span_id = self.id_attr
248
+ project = await info.context.data_loaders.span_projects.load(span_id)
249
+ return to_gql_project(project)
250
+
251
+ @strawberry.field(description="Indicates if the span is contained in any dataset") # type: ignore
252
+ async def contained_in_dataset(self, info: Info[Context, None]) -> bool:
253
+ examples = await info.context.data_loaders.span_dataset_examples.load(self.id_attr)
254
+ return bool(examples)
255
+
256
+ @strawberry.field(description="Invocation parameters for the span") # type: ignore
257
+ async def invocation_parameters(self, info: Info[Context, None]) -> list[InvocationParameter]:
258
+ from phoenix.server.api.helpers.playground_clients import OpenAIStreamingClient
259
+ from phoenix.server.api.helpers.playground_registry import PLAYGROUND_CLIENT_REGISTRY
260
+
261
+ db_span = self.db_span
262
+ attributes = db_span.attributes
263
+ llm_provider = GenerativeProvider.get_model_provider_from_attributes(attributes)
264
+ if llm_provider is None:
265
+ return []
266
+ llm_model = get_attribute_value(attributes, SpanAttributes.LLM_MODEL_NAME)
267
+ invocation_parameters = get_attribute_value(
268
+ attributes, SpanAttributes.LLM_INVOCATION_PARAMETERS
269
+ )
270
+ if invocation_parameters is None:
271
+ return []
272
+ invocation_parameters = json.loads(invocation_parameters)
273
+ # find the client class for the provider, if there is no client class or provider,
274
+ # return openai as default
275
+ client_class = PLAYGROUND_CLIENT_REGISTRY.get_client(llm_provider, llm_model)
276
+ if not client_class:
277
+ client_class = OpenAIStreamingClient
278
+ supported_invocation_parameters = client_class.supported_invocation_parameters()
279
+ # filter supported invocation parameters down to those whose canonical_name is in the
280
+ # invocation_parameters keys
225
281
  return [
226
- to_gql_span(span, self.project)
227
- for span in self.project.get_descendant_spans(SpanID(self.context.span_id))
282
+ ip
283
+ for ip in supported_invocation_parameters
284
+ if (
285
+ ip.canonical_name in invocation_parameters
286
+ or ip.invocation_name in invocation_parameters
287
+ )
228
288
  ]
229
289
 
230
290
 
231
- def to_gql_span(span: WrappedSpan, project: Project) -> "Span":
232
- events: List[SpanEvent] = list(map(SpanEvent.from_event, span.events))
233
- input_value = cast(Optional[str], span.attributes.get(INPUT_VALUE))
234
- output_value = cast(Optional[str], span.attributes.get(OUTPUT_VALUE))
235
- retrieval_documents = span.attributes.get(RETRIEVAL_DOCUMENTS)
291
+ def to_gql_span(span: models.Span) -> Span:
292
+ events: list[SpanEvent] = list(map(SpanEvent.from_dict, span.events))
293
+ input_value = get_attribute_value(span.attributes, INPUT_VALUE)
294
+ if input_value is not None:
295
+ input_value = str(input_value)
296
+ assert input_value is None or isinstance(input_value, str)
297
+ output_value = get_attribute_value(span.attributes, OUTPUT_VALUE)
298
+ if output_value is not None:
299
+ output_value = str(output_value)
300
+ assert output_value is None or isinstance(output_value, str)
301
+ retrieval_documents = get_attribute_value(span.attributes, RETRIEVAL_DOCUMENTS)
236
302
  num_documents = len(retrieval_documents) if isinstance(retrieval_documents, Sized) else None
237
303
  return Span(
238
- project=project,
304
+ id_attr=span.id,
305
+ db_span=span,
239
306
  name=span.name,
240
307
  status_code=SpanStatusCode(span.status_code),
241
308
  status_message=span.status_message,
@@ -243,50 +310,30 @@ def to_gql_span(span: WrappedSpan, project: Project) -> "Span":
243
310
  span_kind=SpanKind(span.span_kind),
244
311
  start_time=span.start_time,
245
312
  end_time=span.end_time,
246
- latency_ms=cast(Optional[float], span[ComputedAttributes.LATENCY_MS]),
313
+ latency_ms=span.latency_ms,
247
314
  context=SpanContext(
248
- trace_id=cast(ID, span.context.trace_id),
249
- span_id=cast(ID, span.context.span_id),
315
+ trace_id=cast(ID, span.trace.trace_id),
316
+ span_id=cast(ID, span.span_id),
250
317
  ),
251
- attributes=json.dumps(
252
- _nested_attributes(_hide_embedding_vectors(span.attributes)),
253
- cls=_JSONEncoder,
254
- ),
255
- metadata=_convert_metadata_to_string(span.attributes.get(METADATA)),
318
+ attributes=json.dumps(_hide_embedding_vectors(span.attributes), cls=_JSONEncoder),
319
+ metadata=_convert_metadata_to_string(get_attribute_value(span.attributes, METADATA)),
256
320
  num_documents=num_documents,
257
- token_count_total=cast(
258
- Optional[int],
259
- span.attributes.get(LLM_TOKEN_COUNT_TOTAL),
260
- ),
261
- token_count_prompt=cast(
262
- Optional[int],
263
- span.attributes.get(LLM_TOKEN_COUNT_PROMPT),
264
- ),
265
- token_count_completion=cast(
266
- Optional[int],
267
- span.attributes.get(LLM_TOKEN_COUNT_COMPLETION),
268
- ),
269
- cumulative_token_count_total=cast(
270
- Optional[int],
271
- span[ComputedAttributes.CUMULATIVE_LLM_TOKEN_COUNT_TOTAL],
272
- ),
273
- cumulative_token_count_prompt=cast(
274
- Optional[int],
275
- span[ComputedAttributes.CUMULATIVE_LLM_TOKEN_COUNT_PROMPT],
276
- ),
277
- cumulative_token_count_completion=cast(
278
- Optional[int],
279
- span[ComputedAttributes.CUMULATIVE_LLM_TOKEN_COUNT_COMPLETION],
280
- ),
321
+ token_count_total=span.llm_token_count_total,
322
+ token_count_prompt=span.llm_token_count_prompt,
323
+ token_count_completion=span.llm_token_count_completion,
324
+ cumulative_token_count_total=span.cumulative_llm_token_count_prompt
325
+ + span.cumulative_llm_token_count_completion,
326
+ cumulative_token_count_prompt=span.cumulative_llm_token_count_prompt,
327
+ cumulative_token_count_completion=span.cumulative_llm_token_count_completion,
281
328
  propagated_status_code=(
282
329
  SpanStatusCode.ERROR
283
- if span[ComputedAttributes.CUMULATIVE_ERROR_COUNT]
330
+ if span.cumulative_error_count
284
331
  else SpanStatusCode(span.status_code)
285
332
  ),
286
333
  events=events,
287
334
  input=(
288
335
  SpanIOValue(
289
- mime_type=MimeType(span.attributes.get(INPUT_MIME_TYPE)),
336
+ mime_type=MimeType(get_attribute_value(span.attributes, INPUT_MIME_TYPE)),
290
337
  value=input_value,
291
338
  )
292
339
  if input_value is not None
@@ -294,7 +341,7 @@ def to_gql_span(span: WrappedSpan, project: Project) -> "Span":
294
341
  ),
295
342
  output=(
296
343
  SpanIOValue(
297
- mime_type=MimeType(span.attributes.get(OUTPUT_MIME_TYPE)),
344
+ mime_type=MimeType(get_attribute_value(span.attributes, OUTPUT_MIME_TYPE)),
298
345
  value=output_value,
299
346
  )
300
347
  if output_value is not None
@@ -303,6 +350,29 @@ def to_gql_span(span: WrappedSpan, project: Project) -> "Span":
303
350
  )
304
351
 
305
352
 
353
+ def _hide_embedding_vectors(attributes: Mapping[str, Any]) -> Mapping[str, Any]:
354
+ if not (
355
+ isinstance(em := attributes.get("embedding"), dict)
356
+ and isinstance(embeddings := em.get("embeddings"), list)
357
+ and embeddings
358
+ ):
359
+ return attributes
360
+ embeddings = embeddings.copy()
361
+ for i, embedding in enumerate(embeddings):
362
+ if not (
363
+ isinstance(embedding, dict)
364
+ and isinstance(emb := embedding.get("embedding"), dict)
365
+ and isinstance(vector := emb.get("vector"), list)
366
+ and vector
367
+ ):
368
+ continue
369
+ embeddings[i] = {
370
+ **embedding,
371
+ "embedding": {**emb, "vector": f"<{len(vector)} dimensional vector>"},
372
+ }
373
+ return {**attributes, "embedding": {**em, "embeddings": embeddings}}
374
+
375
+
306
376
  class _JSONEncoder(json.JSONEncoder):
307
377
  def default(self, obj: Any) -> Any:
308
378
  if isinstance(obj, datetime):
@@ -318,39 +388,6 @@ class _JSONEncoder(json.JSONEncoder):
318
388
  return super().default(obj)
319
389
 
320
390
 
321
- def _trie() -> DefaultDict[str, Any]:
322
- return defaultdict(_trie)
323
-
324
-
325
- def _nested_attributes(
326
- attributes: Mapping[str, Any],
327
- ) -> DefaultDict[str, Any]:
328
- nested_attributes = _trie()
329
- for attribute_name, attribute_value in attributes.items():
330
- trie = nested_attributes
331
- keys = attribute_name.split(".")
332
- for key in keys[:-1]:
333
- trie = trie[key]
334
- trie[keys[-1]] = attribute_value
335
- return nested_attributes
336
-
337
-
338
- def _hide_embedding_vectors(
339
- attributes: Mapping[str, Any],
340
- ) -> Dict[str, Any]:
341
- _attributes = dict(attributes)
342
- if not (embeddings := _attributes.get(EMBEDDING_EMBEDDINGS)):
343
- return _attributes
344
- _embeddings = []
345
- for embedding in embeddings:
346
- _embedding = dict(embedding)
347
- if vector := _embedding.get(EMBEDDING_VECTOR):
348
- _embedding[EMBEDDING_VECTOR] = f"<{len(vector)} dimensional vector>"
349
- _embeddings.append(_embedding)
350
- _attributes[EMBEDDING_EMBEDDINGS] = _embeddings
351
- return _attributes
352
-
353
-
354
391
  def _convert_metadata_to_string(metadata: Any) -> Optional[str]:
355
392
  """
356
393
  Converts metadata to a string representation.
@@ -362,3 +399,11 @@ def _convert_metadata_to_string(metadata: Any) -> Optional[str]:
362
399
  return json.dumps(metadata)
363
400
  except Exception:
364
401
  return str(metadata)
402
+
403
+
404
+ INPUT_MIME_TYPE = SpanAttributes.INPUT_MIME_TYPE
405
+ INPUT_VALUE = SpanAttributes.INPUT_VALUE
406
+ METADATA = SpanAttributes.METADATA
407
+ OUTPUT_MIME_TYPE = SpanAttributes.OUTPUT_MIME_TYPE
408
+ OUTPUT_VALUE = SpanAttributes.OUTPUT_VALUE
409
+ RETRIEVAL_DOCUMENTS = SpanAttributes.RETRIEVAL_DOCUMENTS
@@ -0,0 +1,43 @@
1
+ from typing import Optional
2
+
3
+ import strawberry
4
+ from strawberry import Private
5
+ from strawberry.relay import GlobalID, Node, NodeID
6
+ from strawberry.scalars import JSON
7
+
8
+ from phoenix.db import models
9
+
10
+ from .Annotation import Annotation
11
+ from .AnnotatorKind import AnnotatorKind
12
+
13
+
14
+ @strawberry.type
15
+ class SpanAnnotation(Node, Annotation):
16
+ id_attr: NodeID[int]
17
+ annotator_kind: AnnotatorKind
18
+ metadata: JSON
19
+ span_rowid: Private[Optional[int]]
20
+
21
+ @strawberry.field
22
+ async def span_id(self) -> GlobalID:
23
+ from phoenix.server.api.types.Span import Span
24
+
25
+ return GlobalID(type_name=Span.__name__, node_id=str(self.span_rowid))
26
+
27
+
28
+ def to_gql_span_annotation(
29
+ annotation: models.SpanAnnotation,
30
+ ) -> SpanAnnotation:
31
+ """
32
+ Converts an ORM span annotation to a GraphQL SpanAnnotation.
33
+ """
34
+ return SpanAnnotation(
35
+ id_attr=annotation.id,
36
+ span_rowid=annotation.span_rowid,
37
+ name=annotation.name,
38
+ annotator_kind=AnnotatorKind(annotation.annotator_kind),
39
+ label=annotation.label,
40
+ score=annotation.score,
41
+ explanation=annotation.explanation,
42
+ metadata=annotation.metadata_,
43
+ )
@@ -0,0 +1,15 @@
1
+ import strawberry
2
+
3
+ from phoenix.server.api.types.MimeType import MimeType
4
+
5
+
6
+ @strawberry.type
7
+ class SpanIOValue:
8
+ mime_type: MimeType
9
+ value: str
10
+
11
+ @strawberry.field(
12
+ description="Truncate value up to `chars` characters, appending '...' if truncated.",
13
+ ) # type: ignore
14
+ def truncated_value(self, chars: int = 100) -> str:
15
+ return f"{self.value[: max(0, chars - 3)]}..." if len(self.value) > chars else self.value
@@ -0,0 +1,9 @@
1
+ import strawberry
2
+ from strawberry.relay import Node, NodeID
3
+
4
+ from .ApiKey import ApiKey
5
+
6
+
7
+ @strawberry.type
8
+ class SystemApiKey(ApiKey, Node):
9
+ id_attr: NodeID[int]
@@ -0,0 +1,10 @@
1
+ from enum import Enum
2
+
3
+ import strawberry
4
+
5
+
6
+ @strawberry.enum
7
+ class TemplateLanguage(Enum):
8
+ NONE = "NONE"
9
+ MUSTACHE = "MUSTACHE"
10
+ F_STRING = "F_STRING"