From eaaef2fa03eb87d8265579ce28023fe88754b7ef Mon Sep 17 00:00:00 2001 From: Mikyo King Date: Tue, 30 Jul 2024 12:58:29 -0600 Subject: [PATCH] Add annotations in the aside --- app/src/pages/trace/SpanAside.tsx | 33 ++++++++- .../SpanAsideSpanQuery.graphql.ts | 65 +++++++++++++---- .../__generated__/SpanAside_span.graphql.ts | 71 ++++++++++++++++--- .../__generated__/SpanDetailsQuery.graphql.ts | 9 +-- 4 files changed, 151 insertions(+), 27 deletions(-) diff --git a/app/src/pages/trace/SpanAside.tsx b/app/src/pages/trace/SpanAside.tsx index 11bc14a867..54b65139ab 100644 --- a/app/src/pages/trace/SpanAside.tsx +++ b/app/src/pages/trace/SpanAside.tsx @@ -1,8 +1,10 @@ import React, { PropsWithChildren, useMemo } from "react"; import { graphql, useRefetchableFragment } from "react-relay"; +import { css } from "@emotion/react"; import { Flex, Text, View } from "@arizeai/components"; +import { AnnotationLabel } from "@phoenix/components/annotation"; import { LatencyText } from "@phoenix/components/trace/LatencyText"; import { SpanStatusCodeIcon } from "@phoenix/components/trace/SpanStatusCodeIcon"; import { TokenCount } from "@phoenix/components/trace/TokenCount"; @@ -12,8 +14,15 @@ import { fullTimeFormatter } from "@phoenix/utils/timeFormatUtils"; import { SpanAside_span$key } from "./__generated__/SpanAside_span.graphql"; import { SpanAsideSpanQuery } from "./__generated__/SpanAsideSpanQuery.graphql"; +const annotationListCSS = css` + display: flex; + flex-direction: column; + gap: var(--ac-global-dimension-size-100); + align-items: flex-start; +`; + /** - * + * A component that shows the details of a span that is supplementary to the main span details * @returns */ export function SpanAside(props: { span: SpanAside_span$key }) { @@ -28,6 +37,13 @@ export function SpanAside(props: { span: SpanAside_span$key }) { tokenCountTotal tokenCountPrompt tokenCountCompletion + spanAnnotations { + id + name + label + annotatorKind + score + } } `, props.span @@ -50,6 +66,8 @@ export function SpanAside(props: { span: SpanAside_span$key }) { return endDate.getTime() - startDate.getTime(); }, [endDate, startDate]); const statusColor = useSpanStatusCodeColor(code); + const annotations = data.spanAnnotations; + const hasAnnotations = annotations.length > 0; return ( ) : null} + {hasAnnotations && ( + + +
    + {annotations.map((annotation) => ( +
  • + +
  • + ))} +
+
+
+ )}
); diff --git a/app/src/pages/trace/__generated__/SpanAsideSpanQuery.graphql.ts b/app/src/pages/trace/__generated__/SpanAsideSpanQuery.graphql.ts index 5e8f9fdf9e..2222da3401 100644 --- a/app/src/pages/trace/__generated__/SpanAsideSpanQuery.graphql.ts +++ b/app/src/pages/trace/__generated__/SpanAsideSpanQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<941764d5b2b1ee45d859e0edc02b2d53>> + * @generated SignedSource<<6dabf94682f3c879102ec3789967d9d1>> * @lightSyntaxTransform * @nogrep */ @@ -37,7 +37,14 @@ v1 = [ "name": "id", "variableName": "id" } -]; +], +v2 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; return { "fragment": { "argumentDefinitions": (v0/*: any*/), @@ -90,13 +97,7 @@ return { "kind": "TypeDiscriminator", "abstractKey": "__isNode" }, - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "id", - "storageKey": null - }, + (v2/*: any*/), { "kind": "InlineFragment", "selections": [ @@ -141,6 +142,46 @@ return { "kind": "ScalarField", "name": "tokenCountCompletion", "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "SpanAnnotation", + "kind": "LinkedField", + "name": "spanAnnotations", + "plural": true, + "selections": [ + (v2/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "label", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "annotatorKind", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "score", + "storageKey": null + } + ], + "storageKey": null } ], "type": "Span", @@ -152,16 +193,16 @@ return { ] }, "params": { - "cacheID": "c66beac101f3f1ebbc4f905322dbfda0", + "cacheID": "878027b90513af8f947e6aa408450057", "id": null, "metadata": {}, "name": "SpanAsideSpanQuery", "operationKind": "query", - "text": "query SpanAsideSpanQuery(\n $id: GlobalID!\n) {\n node(id: $id) {\n __typename\n ...SpanAside_span\n __isNode: __typename\n id\n }\n}\n\nfragment SpanAside_span on Span {\n id\n code: statusCode\n startTime\n endTime\n tokenCountTotal\n tokenCountPrompt\n tokenCountCompletion\n}\n" + "text": "query SpanAsideSpanQuery(\n $id: GlobalID!\n) {\n node(id: $id) {\n __typename\n ...SpanAside_span\n __isNode: __typename\n id\n }\n}\n\nfragment SpanAside_span on Span {\n id\n code: statusCode\n startTime\n endTime\n tokenCountTotal\n tokenCountPrompt\n tokenCountCompletion\n spanAnnotations {\n id\n name\n label\n annotatorKind\n score\n }\n}\n" } }; })(); -(node as any).hash = "37b6d5584933520677f8fcb68c0e5810"; +(node as any).hash = "cb5cab60889623d77ad0c96c98b3f8ac"; export default node; diff --git a/app/src/pages/trace/__generated__/SpanAside_span.graphql.ts b/app/src/pages/trace/__generated__/SpanAside_span.graphql.ts index 79de409a07..46b5e3c807 100644 --- a/app/src/pages/trace/__generated__/SpanAside_span.graphql.ts +++ b/app/src/pages/trace/__generated__/SpanAside_span.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<14c81412604c26fb24d0f446ee24402d>> + * @generated SignedSource<> * @lightSyntaxTransform * @nogrep */ @@ -9,12 +9,20 @@ // @ts-nocheck import { ReaderFragment, RefetchableFragment } from 'relay-runtime'; +export type AnnotatorKind = "HUMAN" | "LLM"; export type SpanStatusCode = "ERROR" | "OK" | "UNSET"; import { FragmentRefs } from "relay-runtime"; export type SpanAside_span$data = { readonly code: SpanStatusCode; readonly endTime: string | null; readonly id: string; + readonly spanAnnotations: ReadonlyArray<{ + readonly annotatorKind: AnnotatorKind; + readonly id: string; + readonly label: string | null; + readonly name: string; + readonly score: number | null; + }>; readonly startTime: string; readonly tokenCountCompletion: number | null; readonly tokenCountPrompt: number | null; @@ -28,7 +36,15 @@ export type SpanAside_span$key = { import SpanAsideSpanQuery_graphql from './SpanAsideSpanQuery.graphql'; -const node: ReaderFragment = { +const node: ReaderFragment = (function(){ +var v0 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; +return { "argumentDefinitions": [], "kind": "Fragment", "metadata": { @@ -46,13 +62,7 @@ const node: ReaderFragment = { }, "name": "SpanAside_span", "selections": [ - { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "id", - "storageKey": null - }, + (v0/*: any*/), { "alias": "code", "args": null, @@ -94,12 +104,53 @@ const node: ReaderFragment = { "kind": "ScalarField", "name": "tokenCountCompletion", "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "SpanAnnotation", + "kind": "LinkedField", + "name": "spanAnnotations", + "plural": true, + "selections": [ + (v0/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "label", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "annotatorKind", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "score", + "storageKey": null + } + ], + "storageKey": null } ], "type": "Span", "abstractKey": null }; +})(); -(node as any).hash = "37b6d5584933520677f8fcb68c0e5810"; +(node as any).hash = "cb5cab60889623d77ad0c96c98b3f8ac"; export default node; diff --git a/app/src/pages/trace/__generated__/SpanDetailsQuery.graphql.ts b/app/src/pages/trace/__generated__/SpanDetailsQuery.graphql.ts index 922545a54f..1b92d318e3 100644 --- a/app/src/pages/trace/__generated__/SpanDetailsQuery.graphql.ts +++ b/app/src/pages/trace/__generated__/SpanDetailsQuery.graphql.ts @@ -1,5 +1,5 @@ /** - * @generated SignedSource<<7eb51329b17691743da5b3613ed3c293>> + * @generated SignedSource<<15286f0446f997087c2392d071de7a69>> * @lightSyntaxTransform * @nogrep */ @@ -484,7 +484,8 @@ return { "kind": "ScalarField", "name": "annotatorKind", "storageKey": null - } + }, + (v3/*: any*/) ], "storageKey": null }, @@ -512,12 +513,12 @@ return { ] }, "params": { - "cacheID": "fa2339b82801c134af4c9a75a9543866", + "cacheID": "b1a80a0108c40baebf6e64b811ca0202", "id": null, "metadata": {}, "name": "SpanDetailsQuery", "operationKind": "query", - "text": "query SpanDetailsQuery(\n $spanId: GlobalID!\n) {\n span: node(id: $spanId) {\n __typename\n ... on Span {\n id\n context {\n spanId\n traceId\n }\n name\n spanKind\n statusCode: propagatedStatusCode\n statusMessage\n startTime\n parentId\n latencyMs\n tokenCountTotal\n tokenCountPrompt\n tokenCountCompletion\n input {\n value\n mimeType\n }\n output {\n value\n mimeType\n }\n attributes\n events {\n name\n message\n timestamp\n }\n documentRetrievalMetrics {\n evaluationName\n ndcg\n precision\n hit\n }\n documentEvaluations {\n documentPosition\n name\n label\n score\n explanation\n }\n spanAnnotations {\n name\n }\n ...SpanFeedback_annotations\n ...SpanAside_span\n }\n __isNode: __typename\n id\n }\n}\n\nfragment SpanAside_span on Span {\n id\n code: statusCode\n startTime\n endTime\n tokenCountTotal\n tokenCountPrompt\n tokenCountCompletion\n}\n\nfragment SpanFeedback_annotations on Span {\n spanAnnotations {\n name\n label\n score\n explanation\n annotatorKind\n }\n}\n" + "text": "query SpanDetailsQuery(\n $spanId: GlobalID!\n) {\n span: node(id: $spanId) {\n __typename\n ... on Span {\n id\n context {\n spanId\n traceId\n }\n name\n spanKind\n statusCode: propagatedStatusCode\n statusMessage\n startTime\n parentId\n latencyMs\n tokenCountTotal\n tokenCountPrompt\n tokenCountCompletion\n input {\n value\n mimeType\n }\n output {\n value\n mimeType\n }\n attributes\n events {\n name\n message\n timestamp\n }\n documentRetrievalMetrics {\n evaluationName\n ndcg\n precision\n hit\n }\n documentEvaluations {\n documentPosition\n name\n label\n score\n explanation\n }\n spanAnnotations {\n name\n }\n ...SpanFeedback_annotations\n ...SpanAside_span\n }\n __isNode: __typename\n id\n }\n}\n\nfragment SpanAside_span on Span {\n id\n code: statusCode\n startTime\n endTime\n tokenCountTotal\n tokenCountPrompt\n tokenCountCompletion\n spanAnnotations {\n id\n name\n label\n annotatorKind\n score\n }\n}\n\nfragment SpanFeedback_annotations on Span {\n spanAnnotations {\n name\n label\n score\n explanation\n annotatorKind\n }\n}\n" } }; })();