@mastra/playground-ui 49.1.0-alpha.1 → 49.1.0-alpha.2

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.
Files changed (24) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/components/ChatShell.cjs.js +1 -1
  3. package/dist/components/ChatShell.es.js +1 -1
  4. package/dist/components/MessageScroller.cjs.js +1 -1
  5. package/dist/components/MessageScroller.es.js +1 -1
  6. package/dist/domains/traces/components/trace-data-panel-view.cjs.js +3 -1
  7. package/dist/domains/traces/components/trace-data-panel-view.cjs.js.map +1 -1
  8. package/dist/domains/traces/components/trace-data-panel-view.es.js +3 -1
  9. package/dist/domains/traces/components/trace-data-panel-view.es.js.map +1 -1
  10. package/dist/domains/traces/components/trace-keys-and-values.cjs.js +10 -1
  11. package/dist/domains/traces/components/trace-keys-and-values.cjs.js.map +1 -1
  12. package/dist/domains/traces/components/trace-keys-and-values.es.js +10 -1
  13. package/dist/domains/traces/components/trace-keys-and-values.es.js.map +1 -1
  14. package/dist/{message-scroller-DlVS0FW7.js → message-scroller-D0xet-EH.js} +48 -25
  15. package/dist/message-scroller-D0xet-EH.js.map +1 -0
  16. package/dist/{message-scroller-BssU0EKT.cjs → message-scroller-PIxGmJ34.cjs} +48 -25
  17. package/dist/message-scroller-PIxGmJ34.cjs.map +1 -0
  18. package/dist/src/domains/traces/components/trace-data-panel-view.d.ts +8 -1
  19. package/dist/src/domains/traces/components/trace-keys-and-values.d.ts +9 -1
  20. package/dist/src/ds/components/MessageScroller/message-scroller.d.ts +1 -0
  21. package/dist/style.css +4 -0
  22. package/package.json +7 -7
  23. package/dist/message-scroller-BssU0EKT.cjs.map +0 -1
  24. package/dist/message-scroller-DlVS0FW7.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @mastra/playground-ui
2
2
 
3
+ ## 49.1.0-alpha.2
4
+
5
+ ### Minor Changes
6
+
7
+ - Improved `MessageScroller` so chat transcripts follow the stream. With `autoScroll` on, the reader is carried with the newest output while they sit at the end, and a new user turn brings them back to it. Only scrolling away stops the following — content growing under the reader, or landing above them, no longer moves them or flashes the jump-to-end button. ([#21523](https://github.com/mastra-ai/mastra/pull/21523))
8
+
9
+ A turn opening animates the scroll only for a reader who had scrolled away. Someone already at the end is carried by whatever the turn grows under itself, so a surface can reserve room under a live turn and let its own transition set the pace:
10
+
11
+ ```tsx
12
+ <MessageScrollerProvider autoScroll>
13
+ <MessageScrollerViewport>
14
+ <MessageScrollerContent>
15
+ {/* the viewport is a size container, so a live turn can reserve a share of it */}
16
+ <div className="min-h-[70cqh]">{liveTurn}</div>
17
+ </MessageScrollerContent>
18
+ </MessageScrollerViewport>
19
+ </MessageScrollerProvider>
20
+ ```
21
+
22
+ - Added token and estimated cost totals to full trace details in Studio. Opening a trace now shows input tokens, output tokens, and estimated cost in both the trace side panel and the dedicated trace page, including when the trace is opened from a direct link outside the loaded list. Subtrace panels omit these values because they represent totals for the full trace. ([#21541](https://github.com/mastra-ai/mastra/pull/21541))
23
+
24
+ ### Patch Changes
25
+
26
+ - Updated dependencies [[`7e096f0`](https://github.com/mastra-ai/mastra/commit/7e096f02f0dddbf09b85d306458351245ed2f886), [`8f0a332`](https://github.com/mastra-ai/mastra/commit/8f0a3321bf180368d76fe7b36aa1a8f60f00b6de), [`b098de9`](https://github.com/mastra-ai/mastra/commit/b098de9d7cb9f672e0883a5c716465a3a689693d), [`ef6e295`](https://github.com/mastra-ai/mastra/commit/ef6e295b59bc25a5b61b633a89c97bcfce9fb465), [`208e1b3`](https://github.com/mastra-ai/mastra/commit/208e1b39f30f4b386e494394e9d71d96f0f90241), [`c938d34`](https://github.com/mastra-ai/mastra/commit/c938d34739936c8ecbabd67ad6a4a4396f41c4c6), [`fc76b73`](https://github.com/mastra-ai/mastra/commit/fc76b73b114322ba613c60f138f014b2c0adb414), [`1d9a0ea`](https://github.com/mastra-ai/mastra/commit/1d9a0ea4a9901baee6cd56737243bd6d1f631ac0), [`3667679`](https://github.com/mastra-ai/mastra/commit/3667679db057edfb086846d13369fdda4902ad65), [`49696e8`](https://github.com/mastra-ai/mastra/commit/49696e8e42f870674a0a58f5abcd22cc54dd2864), [`512100a`](https://github.com/mastra-ai/mastra/commit/512100a7d8b7e9c920f2590c6b3612f5de0d3cff), [`9ef432b`](https://github.com/mastra-ai/mastra/commit/9ef432b6faa534b57b0d182a610e13dd9a7123ff), [`b9cf308`](https://github.com/mastra-ai/mastra/commit/b9cf30846f97f99ac1906ee8a68f4f2d117b0378)]:
27
+ - @mastra/core@1.60.0-alpha.2
28
+ - @mastra/client-js@1.40.1-alpha.2
29
+ - @mastra/react@1.4.4-alpha.2
30
+
3
31
  ## 49.1.0-alpha.1
4
32
 
5
33
  ### Minor Changes
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
5
  const jsxRuntime = require('react/jsx-runtime');
6
- const messageScroller = require('../message-scroller-BssU0EKT.cjs');
6
+ const messageScroller = require('../message-scroller-PIxGmJ34.cjs');
7
7
  const utils_cn = require('../cn-vA5sWo9W.cjs');
8
8
 
9
9
  function ChatShellRoot({ className, scroller, ...props }) {
@@ -1,5 +1,5 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { d as MessageScrollerProvider, e as MessageScrollerViewport, M as MessageScroller, a as MessageScrollerButton, b as MessageScrollerContent } from '../message-scroller-DlVS0FW7.js';
2
+ import { d as MessageScrollerProvider, e as MessageScrollerViewport, M as MessageScroller, a as MessageScrollerButton, b as MessageScrollerContent } from '../message-scroller-D0xet-EH.js';
3
3
  import { c as cn } from '../cn-BakJzhuv.js';
4
4
 
5
5
  function ChatShellRoot({ className, scroller, ...props }) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
- const messageScroller = require('../message-scroller-BssU0EKT.cjs');
5
+ const messageScroller = require('../message-scroller-PIxGmJ34.cjs');
6
6
  const messageScrollerHooks = require('../message-scroller-hooks-BxAf8k0Y.cjs');
7
7
 
8
8
 
@@ -1,3 +1,3 @@
1
- export { M as MessageScroller, a as MessageScrollerButton, b as MessageScrollerContent, c as MessageScrollerItem, d as MessageScrollerProvider, e as MessageScrollerViewport } from '../message-scroller-DlVS0FW7.js';
1
+ export { M as MessageScroller, a as MessageScrollerButton, b as MessageScrollerContent, c as MessageScrollerItem, d as MessageScrollerProvider, e as MessageScrollerViewport } from '../message-scroller-D0xet-EH.js';
2
2
  export { u as useMessageScroller, a as useMessageScrollerScrollable, b as useMessageScrollerVisibility, c as useOptionalMessageScroller, d as useOptionalMessageScrollerScrollable, e as useOptionalMessageScrollerVisibility } from '../message-scroller-hooks-D5yxCon2.js';
3
3
  //# sourceMappingURL=MessageScroller.es.js.map
@@ -20,6 +20,7 @@ const utils_truncateString = require('../../../utils/truncate-string.cjs.js');
20
20
  function TraceDataPanelView({
21
21
  traceId,
22
22
  spans,
23
+ usage,
23
24
  isLoading,
24
25
  onClose,
25
26
  onSpanSelect,
@@ -71,6 +72,7 @@ function TraceDataPanelView({
71
72
  () => anchorSpanId ? spans?.find((s) => s.spanId === anchorSpanId) : spans?.find((s) => s.parentSpanId == null),
72
73
  [spans, anchorSpanId]
73
74
  );
75
+ const isSubtrace = anchorSpanId !== void 0 && rootSpan?.parentSpanId != null;
74
76
  const handleSpanClick = (id) => {
75
77
  const newId = selectedSpanId === id ? void 0 : id;
76
78
  setSelectedSpanId(newId);
@@ -135,7 +137,7 @@ function TraceDataPanelView({
135
137
  ] })
136
138
  ] }) }),
137
139
  !collapsed && (isLoading ? /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.LoadingData, { children: "Loading trace..." }) : hierarchicalSpans.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(dataPanel.DataPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsxRuntime.jsxs(dataPanel.DataPanel.Content, { children: [
138
- !isOnTracePage && rootSpan && /* @__PURE__ */ jsxRuntime.jsx(domains_traces_components_traceKeysAndValues.TraceKeysAndValues, { rootSpan, className: "mb-6" }),
140
+ !isOnTracePage && rootSpan && /* @__PURE__ */ jsxRuntime.jsx(domains_traces_components_traceKeysAndValues.TraceKeysAndValues, { rootSpan, usage: isSubtrace ? void 0 : usage, className: "mb-6" }),
139
141
  !isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 flex flex-wrap items-center justify-between gap-4", children: [
140
142
  onEvaluateTrace && /* @__PURE__ */ jsxRuntime.jsxs(Button.Button, { size: "sm", onClick: onEvaluateTrace, children: [
141
143
  /* @__PURE__ */ jsxRuntime.jsx(icons_Icon.Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleGaugeIcon, {}) }),
@@ -1 +1 @@
1
- {"version":3,"file":"trace-data-panel-view.cjs.js","sources":["../../../../src/domains/traces/components/trace-data-panel-view.tsx"],"sourcesContent":["import type { LightSpanRecord } from '@mastra/core/storage';\nimport {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport { formatHierarchicalSpans } from './format-hierarchical-spans';\nimport { TraceKeysAndValues } from './trace-keys-and-values';\nimport { TraceTimeline } from './trace-timeline';\nimport { Button } from '@/ds/components/Button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { Notice } from '@/ds/components/Notice';\nimport { Icon } from '@/ds/icons/Icon';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: LightSpanRecord[] | undefined;\n isLoading?: boolean;\n onClose: () => void;\n onSpanSelect?: (spanId: string | undefined) => void;\n onEvaluateTrace?: () => void;\n /** When set, a \"Save as Dataset Item\" button appears; the consumer owns the dialog. */\n onSaveAsDatasetItem?: (args: { traceId: string; rootSpanId: string | undefined }) => void;\n /** When set, an \"Add tool mocks to item\" button appears; the consumer owns the dialog. */\n onAddTraceMocksToItem?: (args: { traceId: string }) => void;\n initialSpanId?: string | null;\n onPrevious?: () => void;\n onNext?: () => void;\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n placement: TraceDataPanelPlacement;\n timelineChartWidth?: 'wide' | 'default';\n /** When both are provided, renders an \"Open trace page\" button. */\n LinkComponent?: LinkComponent;\n traceHref?: string;\n /**\n * Span treated as the displayed root of the timeline. Required for branch\n * subtrees from `getBranch` where the anchor has a real parent that's outside\n * `spans`. When omitted, the span with no parent is used (trace case).\n */\n anchorSpanId?: string;\n /**\n * Whether to render the \"Evaluating traces and saving them as dataset items is\n * available in Mastra Studio\" info notice when neither `onEvaluateTrace` nor\n * `onSaveAsDatasetItem` is provided. Defaults to `true`. Pass `false` when this\n * panel is rendered inside Studio in a context that intentionally omits those\n * handlers (e.g. inline below an experiment result).\n */\n showUnavailableFeaturesMsg?: boolean;\n}\n\nexport function TraceDataPanelView({\n traceId,\n spans,\n isLoading,\n onClose,\n onSpanSelect,\n onEvaluateTrace,\n onSaveAsDatasetItem,\n onAddTraceMocksToItem,\n initialSpanId,\n onPrevious,\n onNext,\n collapsed: controlledCollapsed,\n onCollapsedChange,\n placement,\n timelineChartWidth = 'default',\n LinkComponent,\n traceHref,\n anchorSpanId,\n showUnavailableFeaturesMsg = true,\n}: TraceDataPanelViewProps) {\n const isOnTracePage = placement === 'trace-page';\n const [internalCollapsed, setInternalCollapsed] = useState(false);\n const collapsed = controlledCollapsed ?? internalCollapsed;\n const setCollapsed = onCollapsedChange ?? setInternalCollapsed;\n\n const { download: downloadTraceJson, isPending: isDownloadingTrace } = useDownloadTraceJson();\n\n const [selectedSpanId, setSelectedSpanId] = useState<string | undefined>(initialSpanId ?? undefined);\n\n // Sync selected span when initialSpanId or trace data changes\n useEffect(() => {\n // No span requested: clear immediately.\n if (!initialSpanId) {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n return;\n }\n // Span requested: wait for trace data before deciding so an in-flight\n // fetch doesn't wipe a URL-provided selection. Callers that default their\n // spans to `[]` while loading only say so through `isLoading`.\n if (isLoading || !spans) return;\n\n const found = spans.find(s => s.spanId === initialSpanId);\n if (found) {\n setSelectedSpanId(initialSpanId);\n onSpanSelect?.(initialSpanId);\n } else {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initialSpanId, spans, isLoading]);\n\n const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(spans ?? [], anchorSpanId), [spans, anchorSpanId]);\n\n const [expandedSpanIds, setExpandedSpanIds] = useState<string[]>([]);\n\n useEffect(() => {\n if (hierarchicalSpans.length > 0) {\n setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));\n }\n }, [hierarchicalSpans]);\n\n const rootSpan = useMemo(\n () => (anchorSpanId ? spans?.find(s => s.spanId === anchorSpanId) : spans?.find(s => s.parentSpanId == null)),\n [spans, anchorSpanId],\n );\n\n const handleSpanClick = (id: string) => {\n const newId = selectedSpanId === id ? undefined : id;\n setSelectedSpanId(newId);\n onSpanSelect?.(newId);\n };\n\n const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;\n\n // Shared across both header layouts (list side panel and full trace page) so a trace can be\n // downloaded from wherever it's being inspected.\n const downloadTraceButton = (\n <Button\n size=\"md\"\n tooltip=\"Download trace JSON\"\n aria-label=\"Download trace JSON\"\n disabled={isDownloadingTrace}\n onClick={() => downloadTraceJson(traceId)}\n >\n {isDownloadingTrace ? <Loader2Icon className=\"animate-spin\" /> : <DownloadIcon />}\n </Button>\n );\n\n return (\n <DataPanel collapsed={collapsed}>\n <DataPanel.Header>\n {isOnTracePage ? (\n <>\n <DataPanel.Heading>Trace Timeline</DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">{downloadTraceButton}</ButtonsGroup>\n </>\n ) : (\n <>\n <DataPanel.Heading>\n Trace <b># {truncateString(traceId, 12)}</b>\n </DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">\n {onCollapsedChange && (\n <Button\n size=\"md\"\n tooltip={collapsed ? 'Expand panel' : 'Collapse panel'}\n onClick={() => setCollapsed(!collapsed)}\n >\n {collapsed ? <ChevronsUpDownIcon /> : <ChevronsDownUpIcon />}\n </Button>\n )}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\n {showOpenTracePageLink && (\n <Button\n as={LinkComponent}\n href={traceHref}\n size=\"md\"\n tooltip=\"Open trace page\"\n aria-label=\"Open trace page\"\n >\n <Link2Icon />\n </Button>\n )}\n {downloadTraceButton}\n <DataPanel.CloseButton onClick={onClose} />\n </ButtonsGroup>\n </>\n )}\n </DataPanel.Header>\n\n {!collapsed &&\n (isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : hierarchicalSpans.length === 0 ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {!isOnTracePage && rootSpan && <TraceKeysAndValues rootSpan={rootSpan} className=\"mb-6\" />}\n\n {!isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && (\n <div className=\"mb-6 flex flex-wrap items-center justify-between gap-4\">\n {onEvaluateTrace && (\n <Button size=\"sm\" onClick={onEvaluateTrace}>\n <Icon>\n <CircleGaugeIcon />\n </Icon>\n Evaluate Trace\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button size=\"sm\" onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}>\n <Icon>\n <SaveIcon />\n </Icon>\n Save as Dataset Item\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button size=\"sm\" onClick={() => onAddTraceMocksToItem({ traceId })}>\n <Icon>\n <WrenchIcon />\n </Icon>\n Add tool mocks to item\n </Button>\n )}\n </div>\n )}\n\n {!isOnTracePage &&\n !onEvaluateTrace &&\n !onSaveAsDatasetItem &&\n !onAddTraceMocksToItem &&\n showUnavailableFeaturesMsg && (\n <Notice variant=\"info\" className=\"mb-6\">\n <Notice.Message>\n Evaluating traces and saving them as dataset items is available in Mastra Studio (local or\n deployed).\n </Notice.Message>\n </Notice>\n )}\n\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n />\n </DataPanel.Content>\n ))}\n </DataPanel>\n );\n}\n"],"names":["useState","useDownloadTraceJson","useEffect","useMemo","formatHierarchicalSpans","getAllSpanIds","jsx","Button","Loader2Icon","DownloadIcon","jsxs","DataPanel","Fragment","ButtonsGroup","truncateString","ChevronsUpDownIcon","ChevronsDownUpIcon","Link2Icon","TraceKeysAndValues","Icon","CircleGaugeIcon","SaveIcon","WrenchIcon","Notice","TraceTimeline"],"mappings":"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"}
1
+ {"version":3,"file":"trace-data-panel-view.cjs.js","sources":["../../../../src/domains/traces/components/trace-data-panel-view.tsx"],"sourcesContent":["import type { LightSpanRecord } from '@mastra/core/storage';\nimport {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport { formatHierarchicalSpans } from './format-hierarchical-spans';\nimport { TraceKeysAndValues } from './trace-keys-and-values';\nimport { TraceTimeline } from './trace-timeline';\nimport { Button } from '@/ds/components/Button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { Notice } from '@/ds/components/Notice';\nimport { Icon } from '@/ds/icons/Icon';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: LightSpanRecord[] | undefined;\n /**\n * Token and estimated-cost totals for the trace (from `useTraceUsage`).\n * Rendered in the trace summary when the panel is in the list side-panel\n * placement; the trace page renders its own `TraceKeysAndValues` instead.\n */\n usage?: TraceUsageSummary;\n isLoading?: boolean;\n onClose: () => void;\n onSpanSelect?: (spanId: string | undefined) => void;\n onEvaluateTrace?: () => void;\n /** When set, a \"Save as Dataset Item\" button appears; the consumer owns the dialog. */\n onSaveAsDatasetItem?: (args: { traceId: string; rootSpanId: string | undefined }) => void;\n /** When set, an \"Add tool mocks to item\" button appears; the consumer owns the dialog. */\n onAddTraceMocksToItem?: (args: { traceId: string }) => void;\n initialSpanId?: string | null;\n onPrevious?: () => void;\n onNext?: () => void;\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n placement: TraceDataPanelPlacement;\n timelineChartWidth?: 'wide' | 'default';\n /** When both are provided, renders an \"Open trace page\" button. */\n LinkComponent?: LinkComponent;\n traceHref?: string;\n /**\n * Span treated as the displayed root of the timeline. Required for branch\n * subtrees from `getBranch` where the anchor has a real parent that's outside\n * `spans`. When omitted, the span with no parent is used (trace case).\n */\n anchorSpanId?: string;\n /**\n * Whether to render the \"Evaluating traces and saving them as dataset items is\n * available in Mastra Studio\" info notice when neither `onEvaluateTrace` nor\n * `onSaveAsDatasetItem` is provided. Defaults to `true`. Pass `false` when this\n * panel is rendered inside Studio in a context that intentionally omits those\n * handlers (e.g. inline below an experiment result).\n */\n showUnavailableFeaturesMsg?: boolean;\n}\n\nexport function TraceDataPanelView({\n traceId,\n spans,\n usage,\n isLoading,\n onClose,\n onSpanSelect,\n onEvaluateTrace,\n onSaveAsDatasetItem,\n onAddTraceMocksToItem,\n initialSpanId,\n onPrevious,\n onNext,\n collapsed: controlledCollapsed,\n onCollapsedChange,\n placement,\n timelineChartWidth = 'default',\n LinkComponent,\n traceHref,\n anchorSpanId,\n showUnavailableFeaturesMsg = true,\n}: TraceDataPanelViewProps) {\n const isOnTracePage = placement === 'trace-page';\n const [internalCollapsed, setInternalCollapsed] = useState(false);\n const collapsed = controlledCollapsed ?? internalCollapsed;\n const setCollapsed = onCollapsedChange ?? setInternalCollapsed;\n\n const { download: downloadTraceJson, isPending: isDownloadingTrace } = useDownloadTraceJson();\n\n const [selectedSpanId, setSelectedSpanId] = useState<string | undefined>(initialSpanId ?? undefined);\n\n // Sync selected span when initialSpanId or trace data changes\n useEffect(() => {\n // No span requested: clear immediately.\n if (!initialSpanId) {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n return;\n }\n // Span requested: wait for trace data before deciding so an in-flight\n // fetch doesn't wipe a URL-provided selection. Callers that default their\n // spans to `[]` while loading only say so through `isLoading`.\n if (isLoading || !spans) return;\n\n const found = spans.find(s => s.spanId === initialSpanId);\n if (found) {\n setSelectedSpanId(initialSpanId);\n onSpanSelect?.(initialSpanId);\n } else {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initialSpanId, spans, isLoading]);\n\n const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(spans ?? [], anchorSpanId), [spans, anchorSpanId]);\n\n const [expandedSpanIds, setExpandedSpanIds] = useState<string[]>([]);\n\n useEffect(() => {\n if (hierarchicalSpans.length > 0) {\n setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));\n }\n }, [hierarchicalSpans]);\n\n const rootSpan = useMemo(\n () => (anchorSpanId ? spans?.find(s => s.spanId === anchorSpanId) : spans?.find(s => s.parentSpanId == null)),\n [spans, anchorSpanId],\n );\n const isSubtrace = anchorSpanId !== undefined && rootSpan?.parentSpanId != null;\n\n const handleSpanClick = (id: string) => {\n const newId = selectedSpanId === id ? undefined : id;\n setSelectedSpanId(newId);\n onSpanSelect?.(newId);\n };\n\n const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;\n\n // Shared across both header layouts (list side panel and full trace page) so a trace can be\n // downloaded from wherever it's being inspected.\n const downloadTraceButton = (\n <Button\n size=\"md\"\n tooltip=\"Download trace JSON\"\n aria-label=\"Download trace JSON\"\n disabled={isDownloadingTrace}\n onClick={() => downloadTraceJson(traceId)}\n >\n {isDownloadingTrace ? <Loader2Icon className=\"animate-spin\" /> : <DownloadIcon />}\n </Button>\n );\n\n return (\n <DataPanel collapsed={collapsed}>\n <DataPanel.Header>\n {isOnTracePage ? (\n <>\n <DataPanel.Heading>Trace Timeline</DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">{downloadTraceButton}</ButtonsGroup>\n </>\n ) : (\n <>\n <DataPanel.Heading>\n Trace <b># {truncateString(traceId, 12)}</b>\n </DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">\n {onCollapsedChange && (\n <Button\n size=\"md\"\n tooltip={collapsed ? 'Expand panel' : 'Collapse panel'}\n onClick={() => setCollapsed(!collapsed)}\n >\n {collapsed ? <ChevronsUpDownIcon /> : <ChevronsDownUpIcon />}\n </Button>\n )}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\n {showOpenTracePageLink && (\n <Button\n as={LinkComponent}\n href={traceHref}\n size=\"md\"\n tooltip=\"Open trace page\"\n aria-label=\"Open trace page\"\n >\n <Link2Icon />\n </Button>\n )}\n {downloadTraceButton}\n <DataPanel.CloseButton onClick={onClose} />\n </ButtonsGroup>\n </>\n )}\n </DataPanel.Header>\n\n {!collapsed &&\n (isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : hierarchicalSpans.length === 0 ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {!isOnTracePage && rootSpan && (\n <TraceKeysAndValues rootSpan={rootSpan} usage={isSubtrace ? undefined : usage} className=\"mb-6\" />\n )}\n\n {!isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && (\n <div className=\"mb-6 flex flex-wrap items-center justify-between gap-4\">\n {onEvaluateTrace && (\n <Button size=\"sm\" onClick={onEvaluateTrace}>\n <Icon>\n <CircleGaugeIcon />\n </Icon>\n Evaluate Trace\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button size=\"sm\" onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}>\n <Icon>\n <SaveIcon />\n </Icon>\n Save as Dataset Item\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button size=\"sm\" onClick={() => onAddTraceMocksToItem({ traceId })}>\n <Icon>\n <WrenchIcon />\n </Icon>\n Add tool mocks to item\n </Button>\n )}\n </div>\n )}\n\n {!isOnTracePage &&\n !onEvaluateTrace &&\n !onSaveAsDatasetItem &&\n !onAddTraceMocksToItem &&\n showUnavailableFeaturesMsg && (\n <Notice variant=\"info\" className=\"mb-6\">\n <Notice.Message>\n Evaluating traces and saving them as dataset items is available in Mastra Studio (local or\n deployed).\n </Notice.Message>\n </Notice>\n )}\n\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n />\n </DataPanel.Content>\n ))}\n </DataPanel>\n );\n}\n"],"names":["useState","useDownloadTraceJson","useEffect","useMemo","formatHierarchicalSpans","getAllSpanIds","jsx","Button","Loader2Icon","DownloadIcon","jsxs","DataPanel","Fragment","ButtonsGroup","truncateString","ChevronsUpDownIcon","ChevronsDownUpIcon","Link2Icon","TraceKeysAndValues","Icon","CircleGaugeIcon","SaveIcon","WrenchIcon","Notice","TraceTimeline"],"mappings":"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"}
@@ -16,6 +16,7 @@ import { truncateString } from '../../../utils/truncate-string.es.js';
16
16
  function TraceDataPanelView({
17
17
  traceId,
18
18
  spans,
19
+ usage,
19
20
  isLoading,
20
21
  onClose,
21
22
  onSpanSelect,
@@ -67,6 +68,7 @@ function TraceDataPanelView({
67
68
  () => anchorSpanId ? spans?.find((s) => s.spanId === anchorSpanId) : spans?.find((s) => s.parentSpanId == null),
68
69
  [spans, anchorSpanId]
69
70
  );
71
+ const isSubtrace = anchorSpanId !== void 0 && rootSpan?.parentSpanId != null;
70
72
  const handleSpanClick = (id) => {
71
73
  const newId = selectedSpanId === id ? void 0 : id;
72
74
  setSelectedSpanId(newId);
@@ -131,7 +133,7 @@ function TraceDataPanelView({
131
133
  ] })
132
134
  ] }) }),
133
135
  !collapsed && (isLoading ? /* @__PURE__ */ jsx(DataPanel.LoadingData, { children: "Loading trace..." }) : hierarchicalSpans.length === 0 ? /* @__PURE__ */ jsx(DataPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsxs(DataPanel.Content, { children: [
134
- !isOnTracePage && rootSpan && /* @__PURE__ */ jsx(TraceKeysAndValues, { rootSpan, className: "mb-6" }),
136
+ !isOnTracePage && rootSpan && /* @__PURE__ */ jsx(TraceKeysAndValues, { rootSpan, usage: isSubtrace ? void 0 : usage, className: "mb-6" }),
135
137
  !isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && /* @__PURE__ */ jsxs("div", { className: "mb-6 flex flex-wrap items-center justify-between gap-4", children: [
136
138
  onEvaluateTrace && /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: onEvaluateTrace, children: [
137
139
  /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(CircleGaugeIcon, {}) }),
@@ -1 +1 @@
1
- {"version":3,"file":"trace-data-panel-view.es.js","sources":["../../../../src/domains/traces/components/trace-data-panel-view.tsx"],"sourcesContent":["import type { LightSpanRecord } from '@mastra/core/storage';\nimport {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport { formatHierarchicalSpans } from './format-hierarchical-spans';\nimport { TraceKeysAndValues } from './trace-keys-and-values';\nimport { TraceTimeline } from './trace-timeline';\nimport { Button } from '@/ds/components/Button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { Notice } from '@/ds/components/Notice';\nimport { Icon } from '@/ds/icons/Icon';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: LightSpanRecord[] | undefined;\n isLoading?: boolean;\n onClose: () => void;\n onSpanSelect?: (spanId: string | undefined) => void;\n onEvaluateTrace?: () => void;\n /** When set, a \"Save as Dataset Item\" button appears; the consumer owns the dialog. */\n onSaveAsDatasetItem?: (args: { traceId: string; rootSpanId: string | undefined }) => void;\n /** When set, an \"Add tool mocks to item\" button appears; the consumer owns the dialog. */\n onAddTraceMocksToItem?: (args: { traceId: string }) => void;\n initialSpanId?: string | null;\n onPrevious?: () => void;\n onNext?: () => void;\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n placement: TraceDataPanelPlacement;\n timelineChartWidth?: 'wide' | 'default';\n /** When both are provided, renders an \"Open trace page\" button. */\n LinkComponent?: LinkComponent;\n traceHref?: string;\n /**\n * Span treated as the displayed root of the timeline. Required for branch\n * subtrees from `getBranch` where the anchor has a real parent that's outside\n * `spans`. When omitted, the span with no parent is used (trace case).\n */\n anchorSpanId?: string;\n /**\n * Whether to render the \"Evaluating traces and saving them as dataset items is\n * available in Mastra Studio\" info notice when neither `onEvaluateTrace` nor\n * `onSaveAsDatasetItem` is provided. Defaults to `true`. Pass `false` when this\n * panel is rendered inside Studio in a context that intentionally omits those\n * handlers (e.g. inline below an experiment result).\n */\n showUnavailableFeaturesMsg?: boolean;\n}\n\nexport function TraceDataPanelView({\n traceId,\n spans,\n isLoading,\n onClose,\n onSpanSelect,\n onEvaluateTrace,\n onSaveAsDatasetItem,\n onAddTraceMocksToItem,\n initialSpanId,\n onPrevious,\n onNext,\n collapsed: controlledCollapsed,\n onCollapsedChange,\n placement,\n timelineChartWidth = 'default',\n LinkComponent,\n traceHref,\n anchorSpanId,\n showUnavailableFeaturesMsg = true,\n}: TraceDataPanelViewProps) {\n const isOnTracePage = placement === 'trace-page';\n const [internalCollapsed, setInternalCollapsed] = useState(false);\n const collapsed = controlledCollapsed ?? internalCollapsed;\n const setCollapsed = onCollapsedChange ?? setInternalCollapsed;\n\n const { download: downloadTraceJson, isPending: isDownloadingTrace } = useDownloadTraceJson();\n\n const [selectedSpanId, setSelectedSpanId] = useState<string | undefined>(initialSpanId ?? undefined);\n\n // Sync selected span when initialSpanId or trace data changes\n useEffect(() => {\n // No span requested: clear immediately.\n if (!initialSpanId) {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n return;\n }\n // Span requested: wait for trace data before deciding so an in-flight\n // fetch doesn't wipe a URL-provided selection. Callers that default their\n // spans to `[]` while loading only say so through `isLoading`.\n if (isLoading || !spans) return;\n\n const found = spans.find(s => s.spanId === initialSpanId);\n if (found) {\n setSelectedSpanId(initialSpanId);\n onSpanSelect?.(initialSpanId);\n } else {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initialSpanId, spans, isLoading]);\n\n const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(spans ?? [], anchorSpanId), [spans, anchorSpanId]);\n\n const [expandedSpanIds, setExpandedSpanIds] = useState<string[]>([]);\n\n useEffect(() => {\n if (hierarchicalSpans.length > 0) {\n setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));\n }\n }, [hierarchicalSpans]);\n\n const rootSpan = useMemo(\n () => (anchorSpanId ? spans?.find(s => s.spanId === anchorSpanId) : spans?.find(s => s.parentSpanId == null)),\n [spans, anchorSpanId],\n );\n\n const handleSpanClick = (id: string) => {\n const newId = selectedSpanId === id ? undefined : id;\n setSelectedSpanId(newId);\n onSpanSelect?.(newId);\n };\n\n const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;\n\n // Shared across both header layouts (list side panel and full trace page) so a trace can be\n // downloaded from wherever it's being inspected.\n const downloadTraceButton = (\n <Button\n size=\"md\"\n tooltip=\"Download trace JSON\"\n aria-label=\"Download trace JSON\"\n disabled={isDownloadingTrace}\n onClick={() => downloadTraceJson(traceId)}\n >\n {isDownloadingTrace ? <Loader2Icon className=\"animate-spin\" /> : <DownloadIcon />}\n </Button>\n );\n\n return (\n <DataPanel collapsed={collapsed}>\n <DataPanel.Header>\n {isOnTracePage ? (\n <>\n <DataPanel.Heading>Trace Timeline</DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">{downloadTraceButton}</ButtonsGroup>\n </>\n ) : (\n <>\n <DataPanel.Heading>\n Trace <b># {truncateString(traceId, 12)}</b>\n </DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">\n {onCollapsedChange && (\n <Button\n size=\"md\"\n tooltip={collapsed ? 'Expand panel' : 'Collapse panel'}\n onClick={() => setCollapsed(!collapsed)}\n >\n {collapsed ? <ChevronsUpDownIcon /> : <ChevronsDownUpIcon />}\n </Button>\n )}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\n {showOpenTracePageLink && (\n <Button\n as={LinkComponent}\n href={traceHref}\n size=\"md\"\n tooltip=\"Open trace page\"\n aria-label=\"Open trace page\"\n >\n <Link2Icon />\n </Button>\n )}\n {downloadTraceButton}\n <DataPanel.CloseButton onClick={onClose} />\n </ButtonsGroup>\n </>\n )}\n </DataPanel.Header>\n\n {!collapsed &&\n (isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : hierarchicalSpans.length === 0 ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {!isOnTracePage && rootSpan && <TraceKeysAndValues rootSpan={rootSpan} className=\"mb-6\" />}\n\n {!isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && (\n <div className=\"mb-6 flex flex-wrap items-center justify-between gap-4\">\n {onEvaluateTrace && (\n <Button size=\"sm\" onClick={onEvaluateTrace}>\n <Icon>\n <CircleGaugeIcon />\n </Icon>\n Evaluate Trace\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button size=\"sm\" onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}>\n <Icon>\n <SaveIcon />\n </Icon>\n Save as Dataset Item\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button size=\"sm\" onClick={() => onAddTraceMocksToItem({ traceId })}>\n <Icon>\n <WrenchIcon />\n </Icon>\n Add tool mocks to item\n </Button>\n )}\n </div>\n )}\n\n {!isOnTracePage &&\n !onEvaluateTrace &&\n !onSaveAsDatasetItem &&\n !onAddTraceMocksToItem &&\n showUnavailableFeaturesMsg && (\n <Notice variant=\"info\" className=\"mb-6\">\n <Notice.Message>\n Evaluating traces and saving them as dataset items is available in Mastra Studio (local or\n deployed).\n </Notice.Message>\n </Notice>\n )}\n\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n />\n </DataPanel.Content>\n ))}\n </DataPanel>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"trace-data-panel-view.es.js","sources":["../../../../src/domains/traces/components/trace-data-panel-view.tsx"],"sourcesContent":["import type { LightSpanRecord } from '@mastra/core/storage';\nimport {\n CircleGaugeIcon,\n ChevronsDownUpIcon,\n ChevronsUpDownIcon,\n DownloadIcon,\n Link2Icon,\n Loader2Icon,\n SaveIcon,\n WrenchIcon,\n} from 'lucide-react';\nimport { useEffect, useMemo, useState } from 'react';\nimport { getAllSpanIds } from '../hooks/get-all-span-ids';\nimport { useDownloadTraceJson } from '../hooks/use-download-trace-json';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport { formatHierarchicalSpans } from './format-hierarchical-spans';\nimport { TraceKeysAndValues } from './trace-keys-and-values';\nimport { TraceTimeline } from './trace-timeline';\nimport { Button } from '@/ds/components/Button';\nimport { ButtonsGroup } from '@/ds/components/ButtonsGroup';\nimport { DataPanel } from '@/ds/components/DataPanel';\nimport { Notice } from '@/ds/components/Notice';\nimport { Icon } from '@/ds/icons/Icon';\nimport type { LinkComponent } from '@/ds/types/link-component';\nimport { truncateString } from '@/lib/truncate-string';\n\nexport type TraceDataPanelPlacement = 'traces-list' | 'trace-page';\n\nexport interface TraceDataPanelViewProps {\n traceId: string;\n /** Lightweight spans for the trace. Caller fetches via useTraceLightSpans. */\n spans: LightSpanRecord[] | undefined;\n /**\n * Token and estimated-cost totals for the trace (from `useTraceUsage`).\n * Rendered in the trace summary when the panel is in the list side-panel\n * placement; the trace page renders its own `TraceKeysAndValues` instead.\n */\n usage?: TraceUsageSummary;\n isLoading?: boolean;\n onClose: () => void;\n onSpanSelect?: (spanId: string | undefined) => void;\n onEvaluateTrace?: () => void;\n /** When set, a \"Save as Dataset Item\" button appears; the consumer owns the dialog. */\n onSaveAsDatasetItem?: (args: { traceId: string; rootSpanId: string | undefined }) => void;\n /** When set, an \"Add tool mocks to item\" button appears; the consumer owns the dialog. */\n onAddTraceMocksToItem?: (args: { traceId: string }) => void;\n initialSpanId?: string | null;\n onPrevious?: () => void;\n onNext?: () => void;\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n placement: TraceDataPanelPlacement;\n timelineChartWidth?: 'wide' | 'default';\n /** When both are provided, renders an \"Open trace page\" button. */\n LinkComponent?: LinkComponent;\n traceHref?: string;\n /**\n * Span treated as the displayed root of the timeline. Required for branch\n * subtrees from `getBranch` where the anchor has a real parent that's outside\n * `spans`. When omitted, the span with no parent is used (trace case).\n */\n anchorSpanId?: string;\n /**\n * Whether to render the \"Evaluating traces and saving them as dataset items is\n * available in Mastra Studio\" info notice when neither `onEvaluateTrace` nor\n * `onSaveAsDatasetItem` is provided. Defaults to `true`. Pass `false` when this\n * panel is rendered inside Studio in a context that intentionally omits those\n * handlers (e.g. inline below an experiment result).\n */\n showUnavailableFeaturesMsg?: boolean;\n}\n\nexport function TraceDataPanelView({\n traceId,\n spans,\n usage,\n isLoading,\n onClose,\n onSpanSelect,\n onEvaluateTrace,\n onSaveAsDatasetItem,\n onAddTraceMocksToItem,\n initialSpanId,\n onPrevious,\n onNext,\n collapsed: controlledCollapsed,\n onCollapsedChange,\n placement,\n timelineChartWidth = 'default',\n LinkComponent,\n traceHref,\n anchorSpanId,\n showUnavailableFeaturesMsg = true,\n}: TraceDataPanelViewProps) {\n const isOnTracePage = placement === 'trace-page';\n const [internalCollapsed, setInternalCollapsed] = useState(false);\n const collapsed = controlledCollapsed ?? internalCollapsed;\n const setCollapsed = onCollapsedChange ?? setInternalCollapsed;\n\n const { download: downloadTraceJson, isPending: isDownloadingTrace } = useDownloadTraceJson();\n\n const [selectedSpanId, setSelectedSpanId] = useState<string | undefined>(initialSpanId ?? undefined);\n\n // Sync selected span when initialSpanId or trace data changes\n useEffect(() => {\n // No span requested: clear immediately.\n if (!initialSpanId) {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n return;\n }\n // Span requested: wait for trace data before deciding so an in-flight\n // fetch doesn't wipe a URL-provided selection. Callers that default their\n // spans to `[]` while loading only say so through `isLoading`.\n if (isLoading || !spans) return;\n\n const found = spans.find(s => s.spanId === initialSpanId);\n if (found) {\n setSelectedSpanId(initialSpanId);\n onSpanSelect?.(initialSpanId);\n } else {\n setSelectedSpanId(undefined);\n onSpanSelect?.(undefined);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [initialSpanId, spans, isLoading]);\n\n const hierarchicalSpans = useMemo(() => formatHierarchicalSpans(spans ?? [], anchorSpanId), [spans, anchorSpanId]);\n\n const [expandedSpanIds, setExpandedSpanIds] = useState<string[]>([]);\n\n useEffect(() => {\n if (hierarchicalSpans.length > 0) {\n setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));\n }\n }, [hierarchicalSpans]);\n\n const rootSpan = useMemo(\n () => (anchorSpanId ? spans?.find(s => s.spanId === anchorSpanId) : spans?.find(s => s.parentSpanId == null)),\n [spans, anchorSpanId],\n );\n const isSubtrace = anchorSpanId !== undefined && rootSpan?.parentSpanId != null;\n\n const handleSpanClick = (id: string) => {\n const newId = selectedSpanId === id ? undefined : id;\n setSelectedSpanId(newId);\n onSpanSelect?.(newId);\n };\n\n const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;\n\n // Shared across both header layouts (list side panel and full trace page) so a trace can be\n // downloaded from wherever it's being inspected.\n const downloadTraceButton = (\n <Button\n size=\"md\"\n tooltip=\"Download trace JSON\"\n aria-label=\"Download trace JSON\"\n disabled={isDownloadingTrace}\n onClick={() => downloadTraceJson(traceId)}\n >\n {isDownloadingTrace ? <Loader2Icon className=\"animate-spin\" /> : <DownloadIcon />}\n </Button>\n );\n\n return (\n <DataPanel collapsed={collapsed}>\n <DataPanel.Header>\n {isOnTracePage ? (\n <>\n <DataPanel.Heading>Trace Timeline</DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">{downloadTraceButton}</ButtonsGroup>\n </>\n ) : (\n <>\n <DataPanel.Heading>\n Trace <b># {truncateString(traceId, 12)}</b>\n </DataPanel.Heading>\n <ButtonsGroup className=\"ml-auto shrink-0\">\n {onCollapsedChange && (\n <Button\n size=\"md\"\n tooltip={collapsed ? 'Expand panel' : 'Collapse panel'}\n onClick={() => setCollapsed(!collapsed)}\n >\n {collapsed ? <ChevronsUpDownIcon /> : <ChevronsDownUpIcon />}\n </Button>\n )}\n {(onPrevious || onNext) && (\n <DataPanel.NextPrevNav\n onPrevious={onPrevious}\n onNext={onNext}\n previousLabel=\"Previous trace\"\n nextLabel=\"Next trace\"\n />\n )}\n {showOpenTracePageLink && (\n <Button\n as={LinkComponent}\n href={traceHref}\n size=\"md\"\n tooltip=\"Open trace page\"\n aria-label=\"Open trace page\"\n >\n <Link2Icon />\n </Button>\n )}\n {downloadTraceButton}\n <DataPanel.CloseButton onClick={onClose} />\n </ButtonsGroup>\n </>\n )}\n </DataPanel.Header>\n\n {!collapsed &&\n (isLoading ? (\n <DataPanel.LoadingData>Loading trace...</DataPanel.LoadingData>\n ) : hierarchicalSpans.length === 0 ? (\n <DataPanel.NoData>No spans found for this trace.</DataPanel.NoData>\n ) : (\n <DataPanel.Content>\n {!isOnTracePage && rootSpan && (\n <TraceKeysAndValues rootSpan={rootSpan} usage={isSubtrace ? undefined : usage} className=\"mb-6\" />\n )}\n\n {!isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem || onAddTraceMocksToItem) && (\n <div className=\"mb-6 flex flex-wrap items-center justify-between gap-4\">\n {onEvaluateTrace && (\n <Button size=\"sm\" onClick={onEvaluateTrace}>\n <Icon>\n <CircleGaugeIcon />\n </Icon>\n Evaluate Trace\n </Button>\n )}\n {onSaveAsDatasetItem && (\n <Button size=\"sm\" onClick={() => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId })}>\n <Icon>\n <SaveIcon />\n </Icon>\n Save as Dataset Item\n </Button>\n )}\n {onAddTraceMocksToItem && (\n <Button size=\"sm\" onClick={() => onAddTraceMocksToItem({ traceId })}>\n <Icon>\n <WrenchIcon />\n </Icon>\n Add tool mocks to item\n </Button>\n )}\n </div>\n )}\n\n {!isOnTracePage &&\n !onEvaluateTrace &&\n !onSaveAsDatasetItem &&\n !onAddTraceMocksToItem &&\n showUnavailableFeaturesMsg && (\n <Notice variant=\"info\" className=\"mb-6\">\n <Notice.Message>\n Evaluating traces and saving them as dataset items is available in Mastra Studio (local or\n deployed).\n </Notice.Message>\n </Notice>\n )}\n\n <TraceTimeline\n hierarchicalSpans={hierarchicalSpans}\n onSpanClick={handleSpanClick}\n selectedSpanId={selectedSpanId}\n expandedSpanIds={expandedSpanIds}\n setExpandedSpanIds={setExpandedSpanIds}\n chartWidth={timelineChartWidth}\n />\n </DataPanel.Content>\n ))}\n </DataPanel>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
5
  const jsxRuntime = require('react/jsx-runtime');
6
6
  const dateFns = require('date-fns');
7
+ const domains_metrics_components_metricsUtils = require('../../metrics/components/metrics-utils.cjs.js');
7
8
  const dataKeysAndValues = require('../../../data-keys-and-values-sjag88jf.cjs');
8
9
 
9
10
  function computeTraceStatus(span) {
@@ -11,7 +12,7 @@ function computeTraceStatus(span) {
11
12
  if (span.endedAt == null) return "running" /* RUNNING */;
12
13
  return "success" /* SUCCESS */;
13
14
  }
14
- function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }) {
15
+ function TraceKeysAndValues({ rootSpan, usage, numOfCol = 2, className }) {
15
16
  const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;
16
17
  const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;
17
18
  const status = computeTraceStatus(rootSpan);
@@ -38,6 +39,14 @@ function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }) {
38
39
  endedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
39
40
  /* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Key, { children: "Ended at" }),
40
41
  /* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Value, { children: dateFns.format(endedAt, "MMM dd, h:mm:ss.SSS aaa") })
42
+ ] }),
43
+ usage && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
44
+ /* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Key, { children: "Trace input tokens" }),
45
+ /* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Value, { children: usage.inputTokens === void 0 ? "—" : domains_metrics_components_metricsUtils.formatCompact(usage.inputTokens) }),
46
+ /* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Key, { children: "Trace output tokens" }),
47
+ /* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Value, { children: usage.outputTokens === void 0 ? "—" : domains_metrics_components_metricsUtils.formatCompact(usage.outputTokens) }),
48
+ /* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Key, { children: "Trace est. cost" }),
49
+ /* @__PURE__ */ jsxRuntime.jsx(dataKeysAndValues.DataKeysAndValues.Value, { children: usage.estimatedCost === void 0 ? "—" : domains_metrics_components_metricsUtils.formatCost(usage.estimatedCost, usage.costUnit) })
41
50
  ] })
42
51
  ] });
43
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"trace-keys-and-values.cjs.js","sources":["../../../../src/domains/traces/components/trace-keys-and-values.tsx"],"sourcesContent":["import { format } from 'date-fns';\nimport { DataKeysAndValues } from '@/ds/components/DataKeysAndValues';\n\nenum TraceStatus {\n SUCCESS = 'success',\n ERROR = 'error',\n RUNNING = 'running',\n}\n\nfunction computeTraceStatus(span: { error?: unknown; endedAt?: Date | string | null }): TraceStatus {\n if (span.error != null) return TraceStatus.ERROR;\n if (span.endedAt == null) return TraceStatus.RUNNING;\n return TraceStatus.SUCCESS;\n}\n\n/** Lightweight root-span fields available from `useTraceLightSpans`. */\ntype RootSpanSummary = {\n entityId?: string | null;\n entityName?: string | null;\n entityType?: string | null;\n startedAt: Date | string;\n endedAt?: Date | string | null;\n error?: unknown;\n};\n\nexport interface TraceKeysAndValuesProps {\n rootSpan: RootSpanSummary;\n numOfCol?: 1 | 2 | 3;\n className?: string;\n}\n\nexport function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }: TraceKeysAndValuesProps) {\n const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;\n const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;\n const status = computeTraceStatus(rootSpan);\n const statusLabel = status === TraceStatus.ERROR ? 'ERROR' : status === TraceStatus.RUNNING ? 'RUNNING' : 'SUCCESS';\n\n return (\n <DataKeysAndValues numOfCol={numOfCol} className={className}>\n {rootSpan.entityId && (\n <>\n <DataKeysAndValues.Key>Entity Id</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityName || rootSpan.entityId}</DataKeysAndValues.Value>\n </>\n )}\n {rootSpan.entityType && (\n <>\n <DataKeysAndValues.Key>Entity Type</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityType}</DataKeysAndValues.Value>\n </>\n )}\n <DataKeysAndValues.Key>Status</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{statusLabel}</DataKeysAndValues.Value>\n {startedAt && endedAt && (\n <>\n <DataKeysAndValues.Key>Duration</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {`${(endedAt.getTime() - startedAt.getTime()).toLocaleString()}ms`}\n </DataKeysAndValues.Value>\n </>\n )}\n {startedAt && (\n <>\n <DataKeysAndValues.Key>Started at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(startedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {endedAt && (\n <>\n <DataKeysAndValues.Key>Ended at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(endedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n </DataKeysAndValues>\n );\n}\n"],"names":["jsxs","DataKeysAndValues","Fragment","jsx","format"],"mappings":"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"}
1
+ {"version":3,"file":"trace-keys-and-values.cjs.js","sources":["../../../../src/domains/traces/components/trace-keys-and-values.tsx"],"sourcesContent":["import { format } from 'date-fns';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport { formatCompact, formatCost } from '@/domains/metrics/components/metrics-utils';\nimport { DataKeysAndValues } from '@/ds/components/DataKeysAndValues';\n\nenum TraceStatus {\n SUCCESS = 'success',\n ERROR = 'error',\n RUNNING = 'running',\n}\n\nfunction computeTraceStatus(span: { error?: unknown; endedAt?: Date | string | null }): TraceStatus {\n if (span.error != null) return TraceStatus.ERROR;\n if (span.endedAt == null) return TraceStatus.RUNNING;\n return TraceStatus.SUCCESS;\n}\n\n/** Lightweight root-span fields available from `useTraceLightSpans`. */\ntype RootSpanSummary = {\n entityId?: string | null;\n entityName?: string | null;\n entityType?: string | null;\n startedAt: Date | string;\n endedAt?: Date | string | null;\n error?: unknown;\n};\n\nexport interface TraceKeysAndValuesProps {\n rootSpan: RootSpanSummary;\n /**\n * Token and estimated-cost totals aggregated across the trace's model spans\n * (from `useTraceUsage`). When provided, token and cost rows are rendered —\n * with `—` for values the metrics store couldn't produce (e.g. no pricing\n * match or mixed cost units).\n */\n usage?: TraceUsageSummary;\n numOfCol?: 1 | 2 | 3;\n className?: string;\n}\n\nexport function TraceKeysAndValues({ rootSpan, usage, numOfCol = 2, className }: TraceKeysAndValuesProps) {\n const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;\n const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;\n const status = computeTraceStatus(rootSpan);\n const statusLabel = status === TraceStatus.ERROR ? 'ERROR' : status === TraceStatus.RUNNING ? 'RUNNING' : 'SUCCESS';\n\n return (\n <DataKeysAndValues numOfCol={numOfCol} className={className}>\n {rootSpan.entityId && (\n <>\n <DataKeysAndValues.Key>Entity Id</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityName || rootSpan.entityId}</DataKeysAndValues.Value>\n </>\n )}\n {rootSpan.entityType && (\n <>\n <DataKeysAndValues.Key>Entity Type</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityType}</DataKeysAndValues.Value>\n </>\n )}\n <DataKeysAndValues.Key>Status</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{statusLabel}</DataKeysAndValues.Value>\n {startedAt && endedAt && (\n <>\n <DataKeysAndValues.Key>Duration</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {`${(endedAt.getTime() - startedAt.getTime()).toLocaleString()}ms`}\n </DataKeysAndValues.Value>\n </>\n )}\n {startedAt && (\n <>\n <DataKeysAndValues.Key>Started at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(startedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {endedAt && (\n <>\n <DataKeysAndValues.Key>Ended at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(endedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {usage && (\n <>\n <DataKeysAndValues.Key>Trace input tokens</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.inputTokens === undefined ? '—' : formatCompact(usage.inputTokens)}\n </DataKeysAndValues.Value>\n <DataKeysAndValues.Key>Trace output tokens</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.outputTokens === undefined ? '—' : formatCompact(usage.outputTokens)}\n </DataKeysAndValues.Value>\n <DataKeysAndValues.Key>Trace est. cost</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.estimatedCost === undefined ? '—' : formatCost(usage.estimatedCost, usage.costUnit)}\n </DataKeysAndValues.Value>\n </>\n )}\n </DataKeysAndValues>\n );\n}\n"],"names":["jsxs","DataKeysAndValues","Fragment","jsx","format","formatCompact","formatCost"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
2
  import { format } from 'date-fns';
3
+ import { formatCompact, formatCost } from '../../metrics/components/metrics-utils.es.js';
3
4
  import { D as DataKeysAndValues } from '../../../data-keys-and-values-BJynhd6V.js';
4
5
 
5
6
  function computeTraceStatus(span) {
@@ -7,7 +8,7 @@ function computeTraceStatus(span) {
7
8
  if (span.endedAt == null) return "running" /* RUNNING */;
8
9
  return "success" /* SUCCESS */;
9
10
  }
10
- function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }) {
11
+ function TraceKeysAndValues({ rootSpan, usage, numOfCol = 2, className }) {
11
12
  const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;
12
13
  const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;
13
14
  const status = computeTraceStatus(rootSpan);
@@ -34,6 +35,14 @@ function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }) {
34
35
  endedAt && /* @__PURE__ */ jsxs(Fragment, { children: [
35
36
  /* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Ended at" }),
36
37
  /* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: format(endedAt, "MMM dd, h:mm:ss.SSS aaa") })
38
+ ] }),
39
+ usage && /* @__PURE__ */ jsxs(Fragment, { children: [
40
+ /* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Trace input tokens" }),
41
+ /* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: usage.inputTokens === void 0 ? "—" : formatCompact(usage.inputTokens) }),
42
+ /* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Trace output tokens" }),
43
+ /* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: usage.outputTokens === void 0 ? "—" : formatCompact(usage.outputTokens) }),
44
+ /* @__PURE__ */ jsx(DataKeysAndValues.Key, { children: "Trace est. cost" }),
45
+ /* @__PURE__ */ jsx(DataKeysAndValues.Value, { children: usage.estimatedCost === void 0 ? "—" : formatCost(usage.estimatedCost, usage.costUnit) })
37
46
  ] })
38
47
  ] });
39
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"trace-keys-and-values.es.js","sources":["../../../../src/domains/traces/components/trace-keys-and-values.tsx"],"sourcesContent":["import { format } from 'date-fns';\nimport { DataKeysAndValues } from '@/ds/components/DataKeysAndValues';\n\nenum TraceStatus {\n SUCCESS = 'success',\n ERROR = 'error',\n RUNNING = 'running',\n}\n\nfunction computeTraceStatus(span: { error?: unknown; endedAt?: Date | string | null }): TraceStatus {\n if (span.error != null) return TraceStatus.ERROR;\n if (span.endedAt == null) return TraceStatus.RUNNING;\n return TraceStatus.SUCCESS;\n}\n\n/** Lightweight root-span fields available from `useTraceLightSpans`. */\ntype RootSpanSummary = {\n entityId?: string | null;\n entityName?: string | null;\n entityType?: string | null;\n startedAt: Date | string;\n endedAt?: Date | string | null;\n error?: unknown;\n};\n\nexport interface TraceKeysAndValuesProps {\n rootSpan: RootSpanSummary;\n numOfCol?: 1 | 2 | 3;\n className?: string;\n}\n\nexport function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }: TraceKeysAndValuesProps) {\n const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;\n const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;\n const status = computeTraceStatus(rootSpan);\n const statusLabel = status === TraceStatus.ERROR ? 'ERROR' : status === TraceStatus.RUNNING ? 'RUNNING' : 'SUCCESS';\n\n return (\n <DataKeysAndValues numOfCol={numOfCol} className={className}>\n {rootSpan.entityId && (\n <>\n <DataKeysAndValues.Key>Entity Id</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityName || rootSpan.entityId}</DataKeysAndValues.Value>\n </>\n )}\n {rootSpan.entityType && (\n <>\n <DataKeysAndValues.Key>Entity Type</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityType}</DataKeysAndValues.Value>\n </>\n )}\n <DataKeysAndValues.Key>Status</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{statusLabel}</DataKeysAndValues.Value>\n {startedAt && endedAt && (\n <>\n <DataKeysAndValues.Key>Duration</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {`${(endedAt.getTime() - startedAt.getTime()).toLocaleString()}ms`}\n </DataKeysAndValues.Value>\n </>\n )}\n {startedAt && (\n <>\n <DataKeysAndValues.Key>Started at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(startedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {endedAt && (\n <>\n <DataKeysAndValues.Key>Ended at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(endedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n </DataKeysAndValues>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"trace-keys-and-values.es.js","sources":["../../../../src/domains/traces/components/trace-keys-and-values.tsx"],"sourcesContent":["import { format } from 'date-fns';\nimport type { TraceUsageSummary } from '../trace-list-columns';\nimport { formatCompact, formatCost } from '@/domains/metrics/components/metrics-utils';\nimport { DataKeysAndValues } from '@/ds/components/DataKeysAndValues';\n\nenum TraceStatus {\n SUCCESS = 'success',\n ERROR = 'error',\n RUNNING = 'running',\n}\n\nfunction computeTraceStatus(span: { error?: unknown; endedAt?: Date | string | null }): TraceStatus {\n if (span.error != null) return TraceStatus.ERROR;\n if (span.endedAt == null) return TraceStatus.RUNNING;\n return TraceStatus.SUCCESS;\n}\n\n/** Lightweight root-span fields available from `useTraceLightSpans`. */\ntype RootSpanSummary = {\n entityId?: string | null;\n entityName?: string | null;\n entityType?: string | null;\n startedAt: Date | string;\n endedAt?: Date | string | null;\n error?: unknown;\n};\n\nexport interface TraceKeysAndValuesProps {\n rootSpan: RootSpanSummary;\n /**\n * Token and estimated-cost totals aggregated across the trace's model spans\n * (from `useTraceUsage`). When provided, token and cost rows are rendered —\n * with `—` for values the metrics store couldn't produce (e.g. no pricing\n * match or mixed cost units).\n */\n usage?: TraceUsageSummary;\n numOfCol?: 1 | 2 | 3;\n className?: string;\n}\n\nexport function TraceKeysAndValues({ rootSpan, usage, numOfCol = 2, className }: TraceKeysAndValuesProps) {\n const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;\n const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;\n const status = computeTraceStatus(rootSpan);\n const statusLabel = status === TraceStatus.ERROR ? 'ERROR' : status === TraceStatus.RUNNING ? 'RUNNING' : 'SUCCESS';\n\n return (\n <DataKeysAndValues numOfCol={numOfCol} className={className}>\n {rootSpan.entityId && (\n <>\n <DataKeysAndValues.Key>Entity Id</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityName || rootSpan.entityId}</DataKeysAndValues.Value>\n </>\n )}\n {rootSpan.entityType && (\n <>\n <DataKeysAndValues.Key>Entity Type</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{rootSpan.entityType}</DataKeysAndValues.Value>\n </>\n )}\n <DataKeysAndValues.Key>Status</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{statusLabel}</DataKeysAndValues.Value>\n {startedAt && endedAt && (\n <>\n <DataKeysAndValues.Key>Duration</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {`${(endedAt.getTime() - startedAt.getTime()).toLocaleString()}ms`}\n </DataKeysAndValues.Value>\n </>\n )}\n {startedAt && (\n <>\n <DataKeysAndValues.Key>Started at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(startedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {endedAt && (\n <>\n <DataKeysAndValues.Key>Ended at</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>{format(endedAt, 'MMM dd, h:mm:ss.SSS aaa')}</DataKeysAndValues.Value>\n </>\n )}\n {usage && (\n <>\n <DataKeysAndValues.Key>Trace input tokens</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.inputTokens === undefined ? '—' : formatCompact(usage.inputTokens)}\n </DataKeysAndValues.Value>\n <DataKeysAndValues.Key>Trace output tokens</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.outputTokens === undefined ? '—' : formatCompact(usage.outputTokens)}\n </DataKeysAndValues.Value>\n <DataKeysAndValues.Key>Trace est. cost</DataKeysAndValues.Key>\n <DataKeysAndValues.Value>\n {usage.estimatedCost === undefined ? '—' : formatCost(usage.estimatedCost, usage.costUnit)}\n </DataKeysAndValues.Value>\n </>\n )}\n </DataKeysAndValues>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -126,6 +126,9 @@ function MessageScrollerProvider({
126
126
  const [scrollable, setScrollable] = React.useState(DEFAULT_SCROLLABLE);
127
127
  const [visibility, setVisibility] = React.useState(DEFAULT_VISIBILITY);
128
128
  const atEndRef = React.useRef(true);
129
+ const followingRef = React.useRef(true);
130
+ const travellingToEndRef = React.useRef(false);
131
+ const lastScrollTopRef = React.useRef(0);
129
132
  const reachStartArmedRef = React.useRef(false);
130
133
  const reachStartFiredRef = React.useRef(false);
131
134
  const prependAnchorRef = React.useRef(null);
@@ -152,19 +155,29 @@ function MessageScrollerProvider({
152
155
  const publishVisibility = React.useCallback((nextVisibility) => {
153
156
  setVisibility((current) => visibilityMatches(current, nextVisibility) ? current : nextVisibility);
154
157
  }, []);
155
- const updateScrollable = React.useCallback(() => {
156
- if (!viewportElement) {
157
- atEndRef.current = true;
158
- publishScrollable(DEFAULT_SCROLLABLE);
159
- return;
160
- }
161
- const remainingScroll = viewportElement.scrollHeight - viewportElement.scrollTop - viewportElement.clientHeight;
162
- atEndRef.current = remainingScroll < AUTO_SCROLL_ATTACH_THRESHOLD;
163
- publishScrollable({
164
- start: viewportElement.scrollTop > scrollEdgeThreshold,
165
- end: remainingScroll > scrollEdgeThreshold
166
- });
167
- }, [publishScrollable, scrollEdgeThreshold, viewportElement]);
158
+ const updateScrollable = React.useCallback(
159
+ ({ fromScroll = false } = {}) => {
160
+ if (!viewportElement) {
161
+ atEndRef.current = true;
162
+ publishScrollable(DEFAULT_SCROLLABLE);
163
+ return;
164
+ }
165
+ const { clientHeight, scrollHeight, scrollTop } = viewportElement;
166
+ const remainingScroll = scrollHeight - scrollTop - clientHeight;
167
+ const wentBack = scrollTop < lastScrollTopRef.current;
168
+ atEndRef.current = remainingScroll < AUTO_SCROLL_ATTACH_THRESHOLD;
169
+ if (atEndRef.current || wentBack) travellingToEndRef.current = false;
170
+ lastScrollTopRef.current = scrollTop;
171
+ if (fromScroll && !travellingToEndRef.current && (wentBack || atEndRef.current)) {
172
+ followingRef.current = atEndRef.current;
173
+ }
174
+ publishScrollable({
175
+ start: scrollTop > scrollEdgeThreshold,
176
+ end: remainingScroll > scrollEdgeThreshold && !(autoScroll && followingRef.current)
177
+ });
178
+ },
179
+ [autoScroll, publishScrollable, scrollEdgeThreshold, viewportElement]
180
+ );
168
181
  const getOrderedItems = React.useCallback(() => {
169
182
  orderedItemsRef.current ??= orderItemsByDocumentPosition(Array.from(itemsRegistry.entries()));
170
183
  return orderedItemsRef.current;
@@ -227,7 +240,8 @@ function MessageScrollerProvider({
227
240
  }, [updateScrollable, updateVisibility]);
228
241
  const notifyScroll = React.useCallback(() => {
229
242
  const wasScrollable = Boolean(viewportElement && viewportElement.scrollHeight > viewportElement.clientHeight);
230
- syncAfterScroll();
243
+ updateScrollable({ fromScroll: true });
244
+ updateVisibility();
231
245
  if (!viewportElement) return;
232
246
  if (atEndRef.current && wasScrollable) reachStartArmedRef.current = true;
233
247
  if (!reachStartArmedRef.current) return;
@@ -246,14 +260,14 @@ function MessageScrollerProvider({
246
260
  };
247
261
  }
248
262
  onReachStartRef.current();
249
- }, [preserveScrollOnPrepend, reachStartThreshold, syncAfterScroll, viewportElement]);
263
+ }, [preserveScrollOnPrepend, reachStartThreshold, updateScrollable, updateVisibility, viewportElement]);
250
264
  const notifyContentResize = React.useCallback(() => {
251
- const followEnd = autoScroll && defaultScrollAppliedRef.current && atEndRef.current && viewportElement;
265
+ const followEnd = autoScroll && defaultScrollAppliedRef.current && followingRef.current && viewportElement;
252
266
  if (followEnd) {
253
267
  scrollViewportTo(
254
268
  viewportElement,
255
269
  Math.max(0, viewportElement.scrollHeight - viewportElement.clientHeight),
256
- "auto"
270
+ travellingToEndRef.current ? "smooth" : "auto"
257
271
  );
258
272
  }
259
273
  syncAfterScroll();
@@ -292,11 +306,14 @@ function MessageScrollerProvider({
292
306
  const scrollToEnd = React.useCallback(
293
307
  ({ behavior = "auto" } = {}) => {
294
308
  if (!viewportElement) return false;
309
+ followingRef.current = true;
310
+ travellingToEndRef.current = behavior === "smooth";
295
311
  scrollViewportTo(
296
312
  viewportElement,
297
313
  Math.max(0, viewportElement.scrollHeight - viewportElement.clientHeight),
298
314
  behavior
299
315
  );
316
+ syncAfterScroll();
300
317
  scheduleScrollSync(syncAfterScroll);
301
318
  return true;
302
319
  },
@@ -385,6 +402,7 @@ function MessageScrollerProvider({
385
402
  }
386
403
  const applyDefaultScroll = () => {
387
404
  const lastAnchorId = getLastAnchorId();
405
+ followingRef.current = false;
388
406
  let didScroll = false;
389
407
  if (defaultScrollPosition === "start") {
390
408
  didScroll = scrollToStart({ behavior: "auto" });
@@ -427,20 +445,29 @@ function MessageScrollerProvider({
427
445
  React.useLayoutEffect(() => {
428
446
  const lastAnchorId = getLastAnchorId();
429
447
  const lastAnchor = lastAnchorId ? itemsRegistry.get(lastAnchorId) : void 0;
430
- const shouldAnchorNewTurn = turnAnchoringArmedRef.current && lastAnchorId !== void 0 && lastAnchor !== void 0 && !seenAnchorIds.has(lastAnchorId) && !seenAnchorElements.has(lastAnchor.element);
448
+ const opensTurn = turnAnchoringArmedRef.current && lastAnchorId !== void 0 && lastAnchor !== void 0 && !seenAnchorIds.has(lastAnchorId) && !seenAnchorElements.has(lastAnchor.element);
431
449
  for (const [messageId, item] of getOrderedItems()) {
432
450
  if (!item.scrollAnchor) continue;
433
451
  seenAnchorIds.add(messageId);
434
452
  seenAnchorElements.add(item.element);
435
453
  }
436
454
  turnAnchoringArmedRef.current = defaultScrollAppliedRef.current;
437
- if (!shouldAnchorNewTurn || !lastAnchorId) return;
438
- scrollToMessage(lastAnchorId, { align: "start", behavior: "smooth" });
455
+ if (!autoScroll) {
456
+ if (opensTurn && lastAnchorId) scrollToMessage(lastAnchorId, { align: "start", behavior: "smooth" });
457
+ return;
458
+ }
459
+ const wasFollowing = followingRef.current;
460
+ if (opensTurn) followingRef.current = true;
461
+ if (!defaultScrollAppliedRef.current || !followingRef.current) return;
462
+ const catchingUp = opensTurn && !wasFollowing || travellingToEndRef.current;
463
+ scrollToEnd({ behavior: catchingUp ? "smooth" : "auto" });
439
464
  }, [
465
+ autoScroll,
440
466
  getLastAnchorId,
441
467
  getOrderedItems,
442
468
  itemsRegistry,
443
469
  itemsVersion,
470
+ scrollToEnd,
444
471
  scrollToMessage,
445
472
  seenAnchorElements,
446
473
  seenAnchorIds
@@ -456,10 +483,6 @@ function MessageScrollerProvider({
456
483
  const grownBy = viewportElement.scrollHeight - anchor.scrollHeight;
457
484
  if (grownBy > 0) viewportElement.scrollTop = anchor.scrollTop + grownBy;
458
485
  }, [contentElement, itemsVersion, viewportElement]);
459
- React.useLayoutEffect(() => {
460
- if (!autoScroll || !defaultScrollAppliedRef.current || !atEndRef.current) return;
461
- scrollToEnd({ behavior: "auto" });
462
- }, [autoScroll, itemsVersion, scrollToEnd]);
463
486
  const actionsContextValue = React.useMemo(
464
487
  () => ({
465
488
  notifyContentResize,
@@ -643,4 +666,4 @@ const MessageScrollerButton = React.forwardRef(
643
666
  MessageScrollerButton.displayName = "MessageScrollerButton";
644
667
 
645
668
  export { MessageScroller as M, MessageScrollerButton as a, MessageScrollerContent as b, MessageScrollerItem as c, MessageScrollerProvider as d, MessageScrollerViewport as e };
646
- //# sourceMappingURL=message-scroller-DlVS0FW7.js.map
669
+ //# sourceMappingURL=message-scroller-D0xet-EH.js.map