diff --git a/app/src/components/trace/SpanItem.tsx b/app/src/components/trace/SpanItem.tsx
index 9482f8c117..4802f55b11 100644
--- a/app/src/components/trace/SpanItem.tsx
+++ b/app/src/components/trace/SpanItem.tsx
@@ -3,8 +3,8 @@ import { css } from "@emotion/react";
import { Flex, Text, View } from "@arizeai/components";
+import { TokenCount } from "@phoenix/components/trace/TokenCount";
import { SpanStatusCode } from "@phoenix/pages/project/__generated__/SpansTable_spans.graphql";
-import { TokenCount } from "@phoenix/pages/project/TokenCount";
import { LatencyText } from "./LatencyText";
import { SpanKindLabel } from "./SpanKindLabel";
diff --git a/app/src/pages/project/TokenCount.tsx b/app/src/components/trace/TokenCount.tsx
similarity index 77%
rename from app/src/pages/project/TokenCount.tsx
rename to app/src/components/trace/TokenCount.tsx
index 36d7a3ae13..f74c30a346 100644
--- a/app/src/pages/project/TokenCount.tsx
+++ b/app/src/components/trace/TokenCount.tsx
@@ -6,6 +6,7 @@ import {
Icon,
Icons,
Text,
+ TextProps,
Tooltip,
TooltipTrigger,
TriggerWrap,
@@ -24,6 +25,10 @@ type TokenCountProps = {
* The number of tokens in the completion
*/
tokenCountCompletion: number;
+ /**
+ * The size of the icon and text
+ */
+ textSize?: TextProps["textSize"];
};
/**
@@ -33,7 +38,7 @@ export function TokenCount(props: TokenCountProps) {
return (
- {props.tokenCountTotal}
+ {props.tokenCountTotal}
@@ -51,16 +56,22 @@ export function TokenCount(props: TokenCountProps) {
);
}
-function TokenItem({ children }: { children: number }) {
+function TokenItem({
+ children,
+ ...textProps
+}: {
+ children: number;
+ textSize?: TextProps["textSize"];
+}) {
return (
-
+
}
css={css`
color: var(--ac-global-text-color-900);
`}
/>
- {children}
+ {children}
);
}
diff --git a/app/src/components/trace/TraceTree.tsx b/app/src/components/trace/TraceTree.tsx
index d1d7684617..9d4a60f87c 100644
--- a/app/src/components/trace/TraceTree.tsx
+++ b/app/src/components/trace/TraceTree.tsx
@@ -3,7 +3,7 @@ import { css } from "@emotion/react";
import { Flex, Text, View } from "@arizeai/components";
-import { TokenCount } from "@phoenix/pages/project/TokenCount";
+import { TokenCount } from "@phoenix/components/trace/TokenCount";
import { LatencyText } from "./LatencyText";
import { SpanKindIcon } from "./SpanKindIcon";
diff --git a/app/src/pages/project/SpansTable.tsx b/app/src/pages/project/SpansTable.tsx
index 2328d6664f..4a9489e180 100644
--- a/app/src/pages/project/SpansTable.tsx
+++ b/app/src/pages/project/SpansTable.tsx
@@ -32,6 +32,7 @@ import { TimestampCell } from "@phoenix/components/table/TimestampCell";
import { LatencyText } from "@phoenix/components/trace/LatencyText";
import { SpanKindLabel } from "@phoenix/components/trace/SpanKindLabel";
import { SpanStatusCodeIcon } from "@phoenix/components/trace/SpanStatusCodeIcon";
+import { TokenCount } from "@phoenix/components/trace/TokenCount";
import { useStreamState } from "@phoenix/contexts/StreamStateContext";
import { useTracingContext } from "@phoenix/contexts/TracingContext";
@@ -52,7 +53,6 @@ import {
EVALS_KEY_SEPARATOR,
getGqlSort,
} from "./tableUtils";
-import { TokenCount } from "./TokenCount";
type SpansTableProps = {
project: SpansTable_spans$key;
};
diff --git a/app/src/pages/project/TracesTable.tsx b/app/src/pages/project/TracesTable.tsx
index 8960d41ffa..7befbadd8d 100644
--- a/app/src/pages/project/TracesTable.tsx
+++ b/app/src/pages/project/TracesTable.tsx
@@ -37,6 +37,7 @@ import { TimestampCell } from "@phoenix/components/table/TimestampCell";
import { LatencyText } from "@phoenix/components/trace/LatencyText";
import { SpanKindLabel } from "@phoenix/components/trace/SpanKindLabel";
import { SpanStatusCodeIcon } from "@phoenix/components/trace/SpanStatusCodeIcon";
+import { TokenCount } from "@phoenix/components/trace/TokenCount";
import { ISpanItem } from "@phoenix/components/trace/types";
import { createSpanTree, SpanTreeNode } from "@phoenix/components/trace/utils";
import { useStreamState } from "@phoenix/contexts/StreamStateContext";
@@ -59,7 +60,6 @@ import {
EVALS_KEY_SEPARATOR,
getGqlSort,
} from "./tableUtils";
-import { TokenCount } from "./TokenCount";
type TracesTableProps = {
project: TracesTable_spans$key;
};
diff --git a/app/src/pages/trace/SpanAside.tsx b/app/src/pages/trace/SpanAside.tsx
new file mode 100644
index 0000000000..258f0dfa2c
--- /dev/null
+++ b/app/src/pages/trace/SpanAside.tsx
@@ -0,0 +1,145 @@
+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";
+import { useSpanStatusCodeColor } from "@phoenix/components/trace/useSpanStatusCodeColor";
+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;
+ padding-top: var(--ac-global-dimension-size-50);
+ 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
+ */
+export function SpanAside(props: { span: SpanAside_span$key }) {
+ const [data] = useRefetchableFragment(
+ graphql`
+ fragment SpanAside_span on Span
+ @refetchable(queryName: "SpanAsideSpanQuery") {
+ id
+ code: statusCode
+ startTime
+ endTime
+ tokenCountTotal
+ tokenCountPrompt
+ tokenCountCompletion
+ spanAnnotations {
+ id
+ name
+ label
+ annotatorKind
+ score
+ }
+ }
+ `,
+ props.span
+ );
+ const {
+ startTime,
+ endTime,
+ code,
+ tokenCountCompletion,
+ tokenCountPrompt,
+ tokenCountTotal,
+ } = data;
+ const startDate = useMemo(() => new Date(startTime), [startTime]);
+ const endDate = useMemo(
+ () => (endTime ? new Date(endTime) : null),
+ [endTime]
+ );
+ const latencyMs = useMemo(() => {
+ if (!endDate) return null;
+ return endDate.getTime() - startDate.getTime();
+ }, [endDate, startDate]);
+ const statusColor = useSpanStatusCodeColor(code);
+ const annotations = data.spanAnnotations;
+ const hasAnnotations = annotations.length > 0;
+ return (
+
+
+
+
+
+
+ {code}
+
+
+
+
+ {fullTimeFormatter(startDate)}
+
+ {endDate && (
+
+ {fullTimeFormatter(endDate)}
+
+ )}
+
+
+ {typeof latencyMs === "number" ? (
+
+ ) : (
+ "--"
+ )}
+
+
+ {tokenCountTotal ? (
+
+
+
+ ) : null}
+ {hasAnnotations && (
+
+
+ {annotations.map((annotation) => (
+ -
+
+
+ ))}
+
+
+ )}
+
+
+ );
+}
+
+function LabeledValue({
+ label,
+ children,
+}: PropsWithChildren<{ label: string }>) {
+ return (
+
+
+ {label}
+
+ {children}
+
+ );
+}
diff --git a/app/src/pages/trace/SpanDetails.tsx b/app/src/pages/trace/SpanDetails.tsx
index 05ad77e7be..b2601f7e88 100644
--- a/app/src/pages/trace/SpanDetails.tsx
+++ b/app/src/pages/trace/SpanDetails.tsx
@@ -36,6 +36,8 @@ import {
TabPane,
Tabs,
Text,
+ Tooltip,
+ TooltipTrigger,
View,
ViewProps,
ViewStyleProps,
@@ -59,9 +61,10 @@ import {
MarkdownDisplayProvider,
} from "@phoenix/components/markdown";
import { SpanKindIcon } from "@phoenix/components/trace";
-import { SpanItem } from "@phoenix/components/trace/SpanItem";
+import { SpanKindLabel } from "@phoenix/components/trace/SpanKindLabel";
import { useNotifySuccess, useTheme } from "@phoenix/contexts";
import { useFeatureFlag } from "@phoenix/contexts/FeatureFlagsContext";
+import { usePreferencesContext } from "@phoenix/contexts/PreferencesContext";
import {
AttributeDocument,
AttributeEmbedding,
@@ -85,6 +88,7 @@ import {
SpanDetailsQuery$data,
} from "./__generated__/SpanDetailsQuery.graphql";
import { EditSpanAnnotationsButton } from "./EditSpanAnnotationsButton";
+import { SpanAside } from "./SpanAside";
import { SpanCodeDropdown } from "./SpanCodeDropdown";
import { SpanFeedback } from "./SpanFeedback";
import { SpanToDatasetExampleDialog } from "./SpanToDatasetExampleDialog";
@@ -195,6 +199,7 @@ export function SpanDetails({
name
}
...SpanFeedback_annotations
+ ...SpanAside_span
}
}
}
@@ -214,6 +219,10 @@ export function SpanDetails({
return spanHasException(span);
}, [span]);
const showAnnotations = useFeatureFlag("annotations");
+ const showSpanAside = usePreferencesContext((store) => store.showSpanAside);
+ const setShowSpanAside = usePreferencesContext(
+ (store) => store.setShowSpanAside
+ );
return (
-
-
+
+
+
+ {span.name}
+
-
+
+
+ }
+ >
-
+
+
+
+
+ {showSpanAside ? : null}
+
*:after {
+ content: "";
+ display: block;
+ height: var(--ac-global-dimension-static-size-400);
+ }
+`;
+
+/**
+ * A wrapper for the span info to style it with the appropriate overflow
+ */
+function SpanInfoWrap({ children }: PropsWithChildren) {
+ return (
+
+ {children}
+
+ );
+}
+
function AddSpanToDatasetButton({ span }: { span: Span }) {
const [dialog, setDialog] = useState(null);
const notifySuccess = useNotifySuccess();
diff --git a/app/src/pages/trace/TraceDetails.tsx b/app/src/pages/trace/TraceDetails.tsx
index d811a74315..a87fa122f9 100644
--- a/app/src/pages/trace/TraceDetails.tsx
+++ b/app/src/pages/trace/TraceDetails.tsx
@@ -250,9 +250,18 @@ function ScrollingTabsWrapper({ children }: PropsWithChildren) {
.ac-tabs {
height: 100%;
overflow: hidden;
+ .ac-tabs__extra {
+ width: 100%;
+ padding-right: var(--ac-global-dimension-size-200);
+ padding-bottom: var(--ac-global-dimension-size-50);
+ }
.ac-tabs__pane-container {
+ min-height: 100%;
height: 100%;
overflow-y: auto;
+ div[role="tabpanel"] {
+ height: 100%;
+ }
}
}
`}
diff --git a/app/src/pages/trace/__generated__/SpanAsideSpanQuery.graphql.ts b/app/src/pages/trace/__generated__/SpanAsideSpanQuery.graphql.ts
new file mode 100644
index 0000000000..2222da3401
--- /dev/null
+++ b/app/src/pages/trace/__generated__/SpanAsideSpanQuery.graphql.ts
@@ -0,0 +1,208 @@
+/**
+ * @generated SignedSource<<6dabf94682f3c879102ec3789967d9d1>>
+ * @lightSyntaxTransform
+ * @nogrep
+ */
+
+/* tslint:disable */
+/* eslint-disable */
+// @ts-nocheck
+
+import { ConcreteRequest, Query } from 'relay-runtime';
+import { FragmentRefs } from "relay-runtime";
+export type SpanAsideSpanQuery$variables = {
+ id: string;
+};
+export type SpanAsideSpanQuery$data = {
+ readonly node: {
+ readonly " $fragmentSpreads": FragmentRefs<"SpanAside_span">;
+ };
+};
+export type SpanAsideSpanQuery = {
+ response: SpanAsideSpanQuery$data;
+ variables: SpanAsideSpanQuery$variables;
+};
+
+const node: ConcreteRequest = (function(){
+var v0 = [
+ {
+ "defaultValue": null,
+ "kind": "LocalArgument",
+ "name": "id"
+ }
+],
+v1 = [
+ {
+ "kind": "Variable",
+ "name": "id",
+ "variableName": "id"
+ }
+],
+v2 = {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "id",
+ "storageKey": null
+};
+return {
+ "fragment": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Fragment",
+ "metadata": null,
+ "name": "SpanAsideSpanQuery",
+ "selections": [
+ {
+ "alias": null,
+ "args": (v1/*: any*/),
+ "concreteType": null,
+ "kind": "LinkedField",
+ "name": "node",
+ "plural": false,
+ "selections": [
+ {
+ "args": null,
+ "kind": "FragmentSpread",
+ "name": "SpanAside_span"
+ }
+ ],
+ "storageKey": null
+ }
+ ],
+ "type": "Query",
+ "abstractKey": null
+ },
+ "kind": "Request",
+ "operation": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Operation",
+ "name": "SpanAsideSpanQuery",
+ "selections": [
+ {
+ "alias": null,
+ "args": (v1/*: any*/),
+ "concreteType": null,
+ "kind": "LinkedField",
+ "name": "node",
+ "plural": false,
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "__typename",
+ "storageKey": null
+ },
+ {
+ "kind": "TypeDiscriminator",
+ "abstractKey": "__isNode"
+ },
+ (v2/*: any*/),
+ {
+ "kind": "InlineFragment",
+ "selections": [
+ {
+ "alias": "code",
+ "args": null,
+ "kind": "ScalarField",
+ "name": "statusCode",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "startTime",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "endTime",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "tokenCountTotal",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "tokenCountPrompt",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "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",
+ "abstractKey": null
+ }
+ ],
+ "storageKey": null
+ }
+ ]
+ },
+ "params": {
+ "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 spanAnnotations {\n id\n name\n label\n annotatorKind\n score\n }\n}\n"
+ }
+};
+})();
+
+(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
new file mode 100644
index 0000000000..46b5e3c807
--- /dev/null
+++ b/app/src/pages/trace/__generated__/SpanAside_span.graphql.ts
@@ -0,0 +1,156 @@
+/**
+ * @generated SignedSource<>
+ * @lightSyntaxTransform
+ * @nogrep
+ */
+
+/* tslint:disable */
+/* eslint-disable */
+// @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;
+ readonly tokenCountTotal: number | null;
+ readonly " $fragmentType": "SpanAside_span";
+};
+export type SpanAside_span$key = {
+ readonly " $data"?: SpanAside_span$data;
+ readonly " $fragmentSpreads": FragmentRefs<"SpanAside_span">;
+};
+
+import SpanAsideSpanQuery_graphql from './SpanAsideSpanQuery.graphql';
+
+const node: ReaderFragment = (function(){
+var v0 = {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "id",
+ "storageKey": null
+};
+return {
+ "argumentDefinitions": [],
+ "kind": "Fragment",
+ "metadata": {
+ "refetch": {
+ "connection": null,
+ "fragmentPathInResult": [
+ "node"
+ ],
+ "operation": SpanAsideSpanQuery_graphql,
+ "identifierInfo": {
+ "identifierField": "id",
+ "identifierQueryVariableName": "id"
+ }
+ }
+ },
+ "name": "SpanAside_span",
+ "selections": [
+ (v0/*: any*/),
+ {
+ "alias": "code",
+ "args": null,
+ "kind": "ScalarField",
+ "name": "statusCode",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "startTime",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "endTime",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "tokenCountTotal",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "tokenCountPrompt",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "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 = "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 f9992e3df6..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<>
+ * @generated SignedSource<<15286f0446f997087c2392d071de7a69>>
* @lightSyntaxTransform
* @nogrep
*/
@@ -64,7 +64,7 @@ export type SpanDetailsQuery$data = {
readonly tokenCountCompletion: number | null;
readonly tokenCountPrompt: number | null;
readonly tokenCountTotal: number | null;
- readonly " $fragmentSpreads": FragmentRefs<"SpanFeedback_annotations">;
+ readonly " $fragmentSpreads": FragmentRefs<"SpanAside_span" | "SpanFeedback_annotations">;
} | {
// This will never be '%other', but we need some
// value in case none of the concrete values match.
@@ -409,6 +409,11 @@ return {
"args": null,
"kind": "FragmentSpread",
"name": "SpanFeedback_annotations"
+ },
+ {
+ "args": null,
+ "kind": "FragmentSpread",
+ "name": "SpanAside_span"
}
],
"type": "Span",
@@ -479,9 +484,24 @@ return {
"kind": "ScalarField",
"name": "annotatorKind",
"storageKey": null
- }
+ },
+ (v3/*: any*/)
],
"storageKey": null
+ },
+ {
+ "alias": "code",
+ "args": null,
+ "kind": "ScalarField",
+ "name": "statusCode",
+ "storageKey": null
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "endTime",
+ "storageKey": null
}
],
"type": "Span",
@@ -493,16 +513,16 @@ return {
]
},
"params": {
- "cacheID": "1a2fd0a554755d7a72f92f71ca891a76",
+ "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 }\n __isNode: __typename\n id\n }\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"
}
};
})();
-(node as any).hash = "b2cb5f7c63f463b9b0e3b6f86724132f";
+(node as any).hash = "eaf52d9b37b1f5a29cae360a05b7c975";
export default node;
diff --git a/app/src/store/preferencesStore.tsx b/app/src/store/preferencesStore.tsx
index d8c7745b2e..1ae1148121 100644
--- a/app/src/store/preferencesStore.tsx
+++ b/app/src/store/preferencesStore.tsx
@@ -28,6 +28,16 @@ export interface PreferencesState extends PreferencesProps {
* @returns
*/
setTraceStreamingEnabled: (traceStreamingEnabled: boolean) => void;
+ /**
+ * Whether or not to show the span aside that contains details about timing, status, etc.
+ * @default true
+ */
+ showSpanAside: boolean;
+ /**
+ * Setter for enabling/disabling the span aside
+ * @param showSpanAside
+ */
+ setShowSpanAside: (showSpanAside: boolean) => void;
}
export const createPreferencesStore = (
@@ -43,6 +53,10 @@ export const createPreferencesStore = (
setTraceStreamingEnabled: (traceStreamingEnabled) => {
set({ traceStreamingEnabled });
},
+ showSpanAside: true,
+ setShowSpanAside: (showSpanAside) => {
+ set({ showSpanAside });
+ },
});
return create()(
persist(devtools(preferencesStore), {