@mastra/playground-ui 21.0.0 → 21.0.1-alpha.1

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.
package/dist/index.css CHANGED
@@ -1657,6 +1657,10 @@
1657
1657
  min-height: var(--spacing-12);
1658
1658
  }
1659
1659
 
1660
+ .min-h-72 {
1661
+ min-height: var(--spacing-72);
1662
+ }
1663
+
1660
1664
  .min-h-\[5\.5rem\] {
1661
1665
  min-height: 5.5rem;
1662
1666
  }
@@ -2345,8 +2349,9 @@
2345
2349
  translate: var(--tw-translate-x) var(--tw-translate-y);
2346
2350
  }
2347
2351
 
2348
- .translate-y-\[-1px\] {
2349
- --tw-translate-y: -1px;
2352
+ .-translate-y-px {
2353
+ --tw-translate-y: calc(var(--spacing-px) * -1);
2354
+ translate: var(--tw-translate-x) var(--tw-translate-y);
2350
2355
  translate: var(--tw-translate-x) var(--tw-translate-y);
2351
2356
  }
2352
2357
 
@@ -2612,8 +2617,8 @@
2612
2617
  grid-template-rows: 2fr 3fr;
2613
2618
  }
2614
2619
 
2615
- .grid-rows-\[4rem_20rem\] {
2616
- grid-template-rows: 4rem 20rem;
2620
+ .grid-rows-\[4rem_1fr\] {
2621
+ grid-template-rows: 4rem 1fr;
2617
2622
  }
2618
2623
 
2619
2624
  .grid-rows-\[auto\] {
@@ -7353,10 +7358,6 @@
7353
7358
  min-width: var(--spacing-64);
7354
7359
  }
7355
7360
 
7356
- .\33 xl\:min-w-\[32rem\] {
7357
- min-width: 32rem;
7358
- }
7359
-
7360
7361
  .\33 xl\:gap-14 {
7361
7362
  gap: var(--spacing-14);
7362
7363
  }
@@ -7728,6 +7729,10 @@
7728
7729
  color: var(--color-white);
7729
7730
  }
7730
7731
 
7732
+ .dark\:opacity-100:is(.dark *) {
7733
+ opacity: 1;
7734
+ }
7735
+
7731
7736
  .dark\:brightness-0:is(.dark *) {
7732
7737
  --tw-brightness: brightness(0%);
7733
7738
  filter: var(--tw-blur, ) var(--tw-brightness, ) var(--tw-contrast, ) var(--tw-grayscale, ) var(--tw-hue-rotate, ) var(--tw-invert, ) var(--tw-saturate, ) var(--tw-sepia, ) var(--tw-drop-shadow, );
package/dist/index.es.js CHANGED
@@ -14612,6 +14612,14 @@ const GroqIcon = (props) => /* @__PURE__ */ jsxs(
14612
14612
  }
14613
14613
  );
14614
14614
 
14615
+ const MastraIcon = (props) => /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 34 21", fill: "none", ...props, children: /* @__PURE__ */ jsx(
14616
+ "path",
14617
+ {
14618
+ d: "M4.49805 11.6934C6.98237 11.6934 8.99609 13.7081 8.99609 16.1924C8.9959 18.6765 6.98225 20.6904 4.49805 20.6904C2.01394 20.6903 0.000196352 18.6765 0 16.1924C0 13.7081 2.01382 11.6935 4.49805 11.6934ZM10.3867 0C12.8709 0 14.8846 2.01388 14.8848 4.49805C14.8848 4.8377 14.847 5.16846 14.7755 5.48643C14.4618 6.88139 14.1953 8.4633 14.9928 9.65L16.2575 11.5319C16.3363 11.6491 16.4727 11.7115 16.6137 11.703C16.7369 11.6957 16.8525 11.6343 16.9214 11.5318L18.1876 9.64717C18.9772 8.47198 18.7236 6.90783 18.4205 5.52484C18.3523 5.21392 18.3164 4.89094 18.3164 4.55957C18.3167 2.07546 20.3313 0.0615234 22.8154 0.0615234C25.2994 0.0617476 27.3132 2.0756 27.3135 4.55957C27.3135 4.93883 27.2665 5.30712 27.178 5.65896C26.8547 6.94441 26.5817 8.37932 27.2446 9.52714L28.459 11.6301C28.4819 11.6697 28.5245 11.6934 28.5703 11.6934C31.0545 11.6935 33.0684 13.7081 33.0684 16.1924C33.0682 18.6765 31.0544 20.6903 28.5703 20.6904C26.0861 20.6904 24.0725 18.6765 24.0723 16.1924C24.0723 15.8049 24.1212 15.4288 24.2133 15.0701C24.5458 13.7746 24.8298 12.3251 24.1609 11.1668L23.0044 9.16384C22.9656 9.09659 22.8931 9.05859 22.8154 9.05859C22.7983 9.05859 22.7824 9.06614 22.7728 9.08033L21.4896 10.9895C20.686 12.1851 20.9622 13.781 21.284 15.1851C21.3582 15.5089 21.3975 15.8461 21.3975 16.1924C21.3973 18.6764 19.3834 20.6902 16.8994 20.6904C14.4152 20.6904 12.4006 18.6765 12.4004 16.1924C12.4004 15.932 12.4226 15.6768 12.4651 15.4286C12.6859 14.14 12.8459 12.7122 12.1167 11.6271L11.2419 10.3253C10.6829 9.49347 9.71913 9.05932 8.78286 8.70188C7.0906 8.05584 5.88867 6.41734 5.88867 4.49805C5.88886 2.0139 7.90254 3.29835e-05 10.3867 0Z",
14619
+ fill: props.fill || "currentColor"
14620
+ }
14621
+ ) });
14622
+
14615
14623
  const MistralIcon = (props) => /* @__PURE__ */ jsxs(
14616
14624
  "svg",
14617
14625
  {
@@ -14846,7 +14854,8 @@ const providerMapToIcon = {
14846
14854
  GROQ: /* @__PURE__ */ jsx(GroqIcon, {}),
14847
14855
  X_GROK: /* @__PURE__ */ jsx(XGroqIcon, {}),
14848
14856
  MISTRAL: /* @__PURE__ */ jsx(MistralIcon, {}),
14849
- netlify: /* @__PURE__ */ jsx(NetlifyIcon, {})
14857
+ netlify: /* @__PURE__ */ jsx(NetlifyIcon, {}),
14858
+ mastra: /* @__PURE__ */ jsx(MastraIcon, {})
14850
14859
  };
14851
14860
 
14852
14861
  const cleanProviderId$1 = (providerId) => {
@@ -14870,12 +14879,13 @@ const ProviderLogo$1 = ({ providerId, className = "", size = 20 }) => {
14870
14879
  perplexity: "perplexity",
14871
14880
  fireworks_ai: "fireworks",
14872
14881
  openrouter: "openrouter",
14873
- netlify: "netlify"
14882
+ netlify: "netlify",
14883
+ mastra: "mastra"
14874
14884
  };
14875
14885
  return iconMap[id] || "DEFAULT";
14876
14886
  };
14877
14887
  const fallbackIcon = getFallbackProviderIcon(cleanedProviderId);
14878
- const isGateway = ["netlify"].includes(cleanProviderId);
14888
+ const isGateway = ["netlify", "mastra"].includes(cleanProviderId);
14879
14889
  if (isGateway || imageError || !providerId) {
14880
14890
  if (providerMapToIcon[fallbackIcon]) {
14881
14891
  return /* @__PURE__ */ jsx(Icon, { children: providerMapToIcon[fallbackIcon] });
@@ -15518,12 +15528,13 @@ const ProviderLogo = ({ providerId, className = "", size = 20 }) => {
15518
15528
  perplexity: "perplexity",
15519
15529
  fireworks_ai: "fireworks",
15520
15530
  openrouter: "openrouter",
15521
- netlify: "netlify"
15531
+ netlify: "netlify",
15532
+ mastra: "mastra"
15522
15533
  };
15523
15534
  return iconMap[id] || "DEFAULT";
15524
15535
  };
15525
15536
  const fallbackIcon = getFallbackProviderIcon(cleanedProviderId);
15526
- const isGateway = ["netlify"].includes(cleanProviderId$1);
15537
+ const isGateway = ["netlify", "mastra"].includes(cleanProviderId$1);
15527
15538
  if (isGateway || imageError || !providerId) {
15528
15539
  if (providerMapToIcon[fallbackIcon]) {
15529
15540
  return /* @__PURE__ */ jsx(Icon, { children: providerMapToIcon[fallbackIcon] });
@@ -19731,8 +19742,9 @@ function ScoreDialog({
19731
19742
  usageContext = "scorerPage"
19732
19743
  }) {
19733
19744
  const [datasetDialogOpen, setDatasetDialogOpen] = useState(false);
19734
- const { Link } = useLinkComponent();
19745
+ const { Link, paths } = useLinkComponent();
19735
19746
  const isCodeBased = isCodeBasedScorer$1(score);
19747
+ const scorerDetailHref = score?.scorerId && score?.entityId ? `${paths.scorerLink(score.scorerId)}?entity=${encodeURIComponent(score.entityId)}&scoreId=${encodeURIComponent(score.id)}` : void 0;
19736
19748
  return /* @__PURE__ */ jsxs(Fragment, { children: [
19737
19749
  /* @__PURE__ */ jsxs(
19738
19750
  SideDialog,
@@ -19795,7 +19807,7 @@ function ScoreDialog({
19795
19807
  ...usageContext === "SpanDialog" ? [
19796
19808
  {
19797
19809
  label: "Scorer",
19798
- value: score?.scorer?.name || "-",
19810
+ value: scorerDetailHref ? /* @__PURE__ */ jsx(Link, { href: scorerDetailHref, children: score?.scorer?.name || "-" }) : score?.scorer?.name || "-",
19799
19811
  key: "scorer-name"
19800
19812
  }
19801
19813
  ] : [],
@@ -23233,11 +23245,11 @@ const AgentObservationalMemory = ({ agentId, resourceId, threadId }) => {
23233
23245
  return threshold.min;
23234
23246
  };
23235
23247
  const isAdaptiveMode = omAgentConfig?.messageTokens !== void 0 && typeof omAgentConfig.messageTokens !== "number";
23236
- const totalBudget = isAdaptiveMode ? getThresholdValue(omAgentConfig?.messageTokens, 1e4) : 0;
23237
- const baseMessageTokens = isAdaptiveMode ? getBaseThresholdValue(omAgentConfig?.messageTokens, 1e4) : void 0;
23238
- const baseObservationTokens = isAdaptiveMode ? getBaseThresholdValue(omAgentConfig?.observationTokens, 3e4) : void 0;
23239
- const messageTokensThreshold = streamProgress?.windows?.active?.messages?.threshold ?? recordConfig?.observation?.messageTokens ?? getThresholdValue(omAgentConfig?.messageTokens, 1e4);
23240
- const configObservationTokens = getThresholdValue(omAgentConfig?.observationTokens, 3e4);
23248
+ const totalBudget = isAdaptiveMode ? getThresholdValue(omAgentConfig?.messageTokens, 3e4) : 0;
23249
+ const baseMessageTokens = isAdaptiveMode ? getBaseThresholdValue(omAgentConfig?.messageTokens, 3e4) : void 0;
23250
+ const baseObservationTokens = isAdaptiveMode ? getBaseThresholdValue(omAgentConfig?.observationTokens, 4e4) : void 0;
23251
+ const messageTokensThreshold = streamProgress?.windows?.active?.messages?.threshold ?? recordConfig?.observation?.messageTokens ?? getThresholdValue(omAgentConfig?.messageTokens, 3e4);
23252
+ const configObservationTokens = getThresholdValue(omAgentConfig?.observationTokens, 4e4);
23241
23253
  const observationTokensThreshold = streamProgress?.windows?.active?.observations?.threshold ?? recordConfig?.reflection?.observationTokens ?? configObservationTokens;
23242
23254
  const pendingMessageTokens = streamProgress?.windows?.active?.messages?.tokens ?? record?.pendingMessageTokens ?? 0;
23243
23255
  const observationTokenCount = streamProgress?.windows?.active?.observations?.tokens ?? record?.observationTokenCount ?? 0;
@@ -23868,7 +23880,8 @@ const MemorySearch = ({
23868
23880
  ] });
23869
23881
  };
23870
23882
 
23871
- function AgentMemory({ agentId, threadId }) {
23883
+ function AgentMemory({ agentId, threadId, memoryType }) {
23884
+ const isGatewayMemory = memoryType === "gateway";
23872
23885
  const { threadInput: chatInputValue } = useThreadInput();
23873
23886
  const { paths, navigate } = useLinkComponent();
23874
23887
  const { data: thread } = useThread({ threadId, agentId });
@@ -23932,7 +23945,7 @@ function AgentMemory({ agentId, threadId }) {
23932
23945
  ] })
23933
23946
  ] }) }),
23934
23947
  isOMEnabled && /* @__PURE__ */ jsx("div", { className: "border-b border-border1 min-w-0 overflow-hidden", children: /* @__PURE__ */ jsx(AgentObservationalMemory, { agentId, resourceId: effectiveResourceId, threadId }) }),
23935
- /* @__PURE__ */ jsxs("div", { className: "p-4 border-b border-border1", children: [
23948
+ !isGatewayMemory && /* @__PURE__ */ jsxs("div", { className: "p-4 border-b border-border1", children: [
23936
23949
  /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
23937
23950
  /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-neutral5", children: "Semantic Recall" }),
23938
23951
  searchMemoryData?.searchScope && /* @__PURE__ */ jsx(
@@ -23973,10 +23986,17 @@ function AgentMemory({ agentId, threadId }) {
23973
23986
  )
23974
23987
  ] })
23975
23988
  ] }),
23976
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
23989
+ !isGatewayMemory && /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
23977
23990
  /* @__PURE__ */ jsx(AgentWorkingMemory, { agentId }),
23978
23991
  /* @__PURE__ */ jsx("div", { className: "border-t border-border1", children: /* @__PURE__ */ jsx(AgentMemoryConfig, { agentId }) })
23979
- ] })
23992
+ ] }),
23993
+ isGatewayMemory && /* @__PURE__ */ jsx("div", { className: "p-4 border-b border-border1", children: /* @__PURE__ */ jsxs("div", { className: "bg-surface3 border border-border1 rounded-lg p-4", children: [
23994
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1", children: [
23995
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium px-2 py-0.5 rounded bg-green-500/20 text-green-400", children: "Gateway" }),
23996
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-neutral5", children: "Memory Gateway" })
23997
+ ] }),
23998
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-neutral3", children: "Memory is managed by the Memory Gateway. Threads and observations are stored remotely." })
23999
+ ] }) })
23980
24000
  ] });
23981
24001
  }
23982
24002
 
@@ -24001,7 +24021,7 @@ function AgentInformation({ agentId, threadId }) {
24001
24021
  /* @__PURE__ */ jsx(TabContent, { value: "overview", children: /* @__PURE__ */ jsx(AgentMetadata, { agentId }) }),
24002
24022
  /* @__PURE__ */ jsx(TabContent, { value: "model-settings", children: /* @__PURE__ */ jsx(AgentSettings, { agentId }) }),
24003
24023
  agent?.requestContextSchema && /* @__PURE__ */ jsx(TabContent, { value: "request-context", children: /* @__PURE__ */ jsx("div", { className: "p-5", children: /* @__PURE__ */ jsx(RequestContextSchemaForm, { requestContextSchema: agent.requestContextSchema }) }) }),
24004
- hasMemory && /* @__PURE__ */ jsx(TabContent, { value: "memory", children: /* @__PURE__ */ jsx(AgentMemory, { agentId, threadId }) }),
24024
+ hasMemory && /* @__PURE__ */ jsx(TabContent, { value: "memory", children: /* @__PURE__ */ jsx(AgentMemory, { agentId, threadId, memoryType: memory?.memoryType }) }),
24005
24025
  /* @__PURE__ */ jsx(TabContent, { value: "tracing-options", children: /* @__PURE__ */ jsx(TracingRunOptions, {}) })
24006
24026
  ] }) })
24007
24027
  ] });
@@ -34435,7 +34455,10 @@ function TraceDialog({
34435
34455
  if (initialSpanId) {
34436
34456
  setSelectedSpanId(initialSpanId);
34437
34457
  setDialogIsOpen(true);
34458
+ return;
34438
34459
  }
34460
+ setSelectedSpanId(void 0);
34461
+ setDialogIsOpen(false);
34439
34462
  }, [initialSpanId]);
34440
34463
  useEffect(() => {
34441
34464
  if (spanScoresPage > 0) {
@@ -34466,11 +34489,17 @@ function TraceDialog({
34466
34489
  });
34467
34490
  const handleSpanClick = (id) => {
34468
34491
  if (selectedSpanId === id) {
34492
+ if (traceId) {
34493
+ navigate(computeTraceLink(traceId));
34494
+ }
34469
34495
  setSelectedSpanId(void 0);
34470
- } else {
34471
- setSelectedSpanId(id);
34472
- setSpanDialogDefaultTab("details");
34473
- setDialogIsOpen(true);
34496
+ return;
34497
+ }
34498
+ setSelectedSpanId(id);
34499
+ setSpanDialogDefaultTab("details");
34500
+ setDialogIsOpen(true);
34501
+ if (traceId) {
34502
+ navigate(computeTraceLink(traceId, id));
34474
34503
  }
34475
34504
  };
34476
34505
  const handleToScoring = () => {
@@ -39703,11 +39732,31 @@ function BulkAddToDatasetBar({
39703
39732
  ] })
39704
39733
  ] });
39705
39734
  }
39706
- function AgentTracesPanel({ agentId }) {
39735
+ function AgentTracesPanel({
39736
+ agentId,
39737
+ basePath,
39738
+ initialTraceId,
39739
+ initialSpanId,
39740
+ initialSpanTab,
39741
+ initialScoreId
39742
+ }) {
39707
39743
  const client = useMastraClient();
39708
39744
  const filters = useAgentTracesFilters(agentId);
39709
- const [selectedTraceId, setSelectedTraceId] = useState();
39710
- const [dialogIsOpen, setDialogIsOpen] = useState(false);
39745
+ const { navigate } = useLinkComponent();
39746
+ const buildTraceUrl = useCallback(
39747
+ (traceId, spanId, scoreId, tab) => {
39748
+ const params = new URLSearchParams();
39749
+ if (traceId) params.set("traceId", traceId);
39750
+ if (spanId) params.set("spanId", spanId);
39751
+ if (tab) params.set("tab", tab);
39752
+ if (scoreId) params.set("scoreId", scoreId);
39753
+ const query = params.toString();
39754
+ return query ? `${basePath ?? `/agents/${agentId}/traces`}?${query}` : basePath ?? `/agents/${agentId}/traces`;
39755
+ },
39756
+ [agentId, basePath]
39757
+ );
39758
+ const [selectedTraceId, setSelectedTraceId] = useState(initialTraceId);
39759
+ const [dialogIsOpen, setDialogIsOpen] = useState(Boolean(initialTraceId));
39711
39760
  const [checkedTraceIds, setCheckedTraceIds] = useState(/* @__PURE__ */ new Set());
39712
39761
  const [sort, setSort] = useState(null);
39713
39762
  const {
@@ -39820,20 +39869,31 @@ function AgentTracesPanel({ agentId }) {
39820
39869
  return next.size === prev.size ? prev : next;
39821
39870
  });
39822
39871
  }, [displayTraces, checkedTraceIds.size]);
39872
+ useEffect(() => {
39873
+ if (initialTraceId) {
39874
+ setSelectedTraceId(initialTraceId);
39875
+ setDialogIsOpen(true);
39876
+ return;
39877
+ }
39878
+ setSelectedTraceId(void 0);
39879
+ setDialogIsOpen(false);
39880
+ }, [initialTraceId]);
39823
39881
  const { batchInsertItems } = useDatasetMutations();
39824
39882
  const allSelected = displayTraces.length > 0 && displayTraces.every((t) => checkedTraceIds.has(t.traceId));
39825
39883
  const someSelected = checkedTraceIds.size > 0;
39826
39884
  const handleTraceClick = useCallback(
39827
39885
  (traceId) => {
39828
39886
  if (selectedTraceId === traceId) {
39887
+ navigate(buildTraceUrl());
39829
39888
  setSelectedTraceId(void 0);
39830
39889
  setDialogIsOpen(false);
39831
39890
  } else {
39891
+ navigate(buildTraceUrl(traceId));
39832
39892
  setSelectedTraceId(traceId);
39833
39893
  setDialogIsOpen(true);
39834
39894
  }
39835
39895
  },
39836
- [selectedTraceId]
39896
+ [buildTraceUrl, navigate, selectedTraceId]
39837
39897
  );
39838
39898
  const handleCheckToggle = useCallback((traceId, checked) => {
39839
39899
  setCheckedTraceIds((prev) => {
@@ -39872,14 +39932,16 @@ function AgentTracesPanel({ agentId }) {
39872
39932
  },
39873
39933
  [displayTraces, checkedTraceIds, batchInsertItems]
39874
39934
  );
39875
- const computeTraceLink = useCallback((traceId, spanId) => {
39876
- return `/observability?traceId=${traceId}${spanId ? `&spanId=${spanId}` : ""}`;
39877
- }, []);
39935
+ const computeTraceLink = useCallback(
39936
+ (traceId, spanId, tab) => buildTraceUrl(traceId, spanId, void 0, tab),
39937
+ [buildTraceUrl]
39938
+ );
39878
39939
  const toNextTrace = useMemo(
39879
39940
  () => getToNextEntryFn({
39880
39941
  entries: displayTraces.map((t) => ({ id: t.traceId })),
39881
39942
  id: selectedTraceId,
39882
39943
  update: (id) => {
39944
+ navigate(buildTraceUrl(id));
39883
39945
  setSelectedTraceId(id);
39884
39946
  setDialogIsOpen(true);
39885
39947
  }
@@ -39891,6 +39953,7 @@ function AgentTracesPanel({ agentId }) {
39891
39953
  entries: displayTraces.map((t) => ({ id: t.traceId })),
39892
39954
  id: selectedTraceId,
39893
39955
  update: (id) => {
39956
+ navigate(buildTraceUrl(id));
39894
39957
  setSelectedTraceId(id);
39895
39958
  setDialogIsOpen(true);
39896
39959
  }
@@ -39992,6 +40055,7 @@ function AgentTracesPanel({ agentId }) {
39992
40055
  traceDetails: selectedTrace?.spans?.find((s) => s.traceId === selectedTraceId && !s.parentSpanId),
39993
40056
  isOpen: dialogIsOpen,
39994
40057
  onClose: () => {
40058
+ navigate(buildTraceUrl());
39995
40059
  setDialogIsOpen(false);
39996
40060
  setSelectedTraceId(void 0);
39997
40061
  },
@@ -39999,6 +40063,9 @@ function AgentTracesPanel({ agentId }) {
39999
40063
  onPrevious: toPreviousTrace,
40000
40064
  isLoadingSpans: isSelectedTraceLoading,
40001
40065
  computeTraceLink,
40066
+ initialSpanId,
40067
+ initialSpanTab,
40068
+ initialScoreId,
40002
40069
  scorers: scorersMap,
40003
40070
  isLoadingScorers
40004
40071
  }
@@ -41855,7 +41922,7 @@ function MetricsCardRoot({ children, className }) {
41855
41922
  DashboardCard,
41856
41923
  {
41857
41924
  className: cn(
41858
- "flex-1 grid grid-rows-[4rem_20rem] gap-2 min-w-80 md:min-w-[22rem] lg:min-w-[24rem] xl:min-w-[26rem] 2xl:min-w-[30rem] 3xl:min-w-[32rem]",
41925
+ "flex-1 grid grid-rows-[4rem_1fr] min-h-72 gap-2 min-w-80 md:min-w-[22rem] lg:min-w-[24rem] xl:min-w-[26rem] 2xl:min-w-[30rem]",
41859
41926
  className
41860
41927
  ),
41861
41928
  children
@@ -42006,12 +42073,12 @@ function MetricsLineChart({
42006
42073
  yDomain
42007
42074
  }) {
42008
42075
  return /* @__PURE__ */ jsxs("div", { children: [
42009
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap w-full items-end gap-4 gap-y-1 mb-4", children: series.map((s) => {
42076
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap w-full items-end gap-4 gap-y-1 mb-4 ", children: series.map((s) => {
42010
42077
  const aggregated = s.aggregate?.(data);
42011
42078
  return /* @__PURE__ */ jsxs("div", { className: "inline-flex items-baseline gap-2", children: [
42012
- /* @__PURE__ */ jsx("div", { className: "size-2 shrink-0 rounded-full translate-y-[-1px]", style: { backgroundColor: s.color } }),
42079
+ /* @__PURE__ */ jsx("div", { className: "size-2 shrink-0 rounded-full -translate-y-px", style: { backgroundColor: s.color } }),
42013
42080
  /* @__PURE__ */ jsx("span", { className: "text-ui-sm text-neutral3 truncate max-w-24", children: s.label }),
42014
- aggregated && /* @__PURE__ */ jsxs("span", { className: "text-ui-lg text-neutral4", children: [
42081
+ aggregated && /* @__PURE__ */ jsxs("span", { className: "text-ui-sm text-neutral4", children: [
42015
42082
  aggregated.value,
42016
42083
  aggregated.suffix && /* @__PURE__ */ jsxs("span", { className: "text-ui-sm text-neutral2", children: [
42017
42084
  " ",
@@ -42021,7 +42088,15 @@ function MetricsLineChart({
42021
42088
  ] }, s.dataKey);
42022
42089
  }) }),
42023
42090
  /* @__PURE__ */ jsx("div", { style: { height }, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs(LineChart, { data, children: [
42024
- /* @__PURE__ */ jsx(CartesianGrid, { stroke: "rgba(255,255,255,0.08)", vertical: false }),
42091
+ /* @__PURE__ */ jsx(
42092
+ CartesianGrid,
42093
+ {
42094
+ stroke: "currentColor",
42095
+ strokeOpacity: 0.08,
42096
+ vertical: false,
42097
+ className: "text-black dark:text-white"
42098
+ }
42099
+ ),
42025
42100
  /* @__PURE__ */ jsx(
42026
42101
  XAxis,
42027
42102
  {
@@ -42132,24 +42207,25 @@ function useAvgScoreKpiMetrics() {
42132
42207
  if (scorerIds.length === 0) {
42133
42208
  return { value: null, previousValue: null, changePercent: null };
42134
42209
  }
42135
- const allResults = await Promise.all(
42136
- scorerIds.map((scorerId) => client.listScoresByScorerId({ scorerId, perPage: 100 }))
42210
+ const filters = {
42211
+ timestamp: { start: timestamp.start, end: timestamp.end }
42212
+ };
42213
+ const results = await Promise.all(
42214
+ scorerIds.map(async (scorerId) => {
42215
+ const [avg2, count] = await Promise.all([
42216
+ client.getScoreAggregate({ scorerId, aggregation: "avg", filters }),
42217
+ client.getScoreAggregate({ scorerId, aggregation: "count", filters })
42218
+ ]);
42219
+ return { avg: avg2.value ?? 0, count: count.value ?? 0 };
42220
+ })
42137
42221
  );
42138
- const startMs = timestamp.start.getTime();
42139
- const endMs = timestamp.end.getTime();
42140
- const allScoreValues = [];
42141
- for (const result of allResults) {
42142
- for (const s of result?.scores ?? []) {
42143
- const ts = new Date(s.createdAt).getTime();
42144
- if (ts >= startMs && ts <= endMs) {
42145
- allScoreValues.push(s.score);
42146
- }
42147
- }
42148
- }
42149
- if (allScoreValues.length === 0) {
42222
+ const withData = results.filter((r) => r.count > 0);
42223
+ if (withData.length === 0) {
42150
42224
  return { value: null, previousValue: null, changePercent: null };
42151
42225
  }
42152
- const avg = allScoreValues.reduce((sum, v) => sum + v, 0) / allScoreValues.length;
42226
+ const totalCount = withData.reduce((sum, r) => sum + r.count, 0);
42227
+ const weightedSum = withData.reduce((sum, r) => sum + r.avg * r.count, 0);
42228
+ const avg = weightedSum / totalCount;
42153
42229
  return { value: Math.round(avg * 100) / 100, previousValue: null, changePercent: null };
42154
42230
  }
42155
42231
  });
@@ -42428,78 +42504,84 @@ function useScoresMetrics() {
42428
42504
  return useQuery({
42429
42505
  queryKey: ["metrics", "scores-card", datePreset, customRange],
42430
42506
  queryFn: async () => {
42507
+ const filters = {
42508
+ timestamp: { start: timestamp.start, end: timestamp.end }
42509
+ };
42431
42510
  const scorersMap = await client.listScorers();
42432
42511
  const scorerIds = Object.keys(scorersMap ?? {});
42433
42512
  if (scorerIds.length === 0) {
42434
42513
  return { summaryData: [], overTimeData: [], scorerNames: [], avgScore: null };
42435
42514
  }
42436
- const allResults = await Promise.all(
42437
- // Limited to 100 most recent scores per scorer; pagination not yet implemented
42438
- scorerIds.map((scorerId) => client.listScoresByScorerId({ scorerId, perPage: 100 }))
42515
+ const summaryResults = await Promise.all(
42516
+ scorerIds.map(async (scorerId) => {
42517
+ const [avg, min, max, count] = await Promise.all([
42518
+ client.getScoreAggregate({ scorerId, aggregation: "avg", filters }),
42519
+ client.getScoreAggregate({ scorerId, aggregation: "min", filters }),
42520
+ client.getScoreAggregate({ scorerId, aggregation: "max", filters }),
42521
+ client.getScoreAggregate({ scorerId, aggregation: "count", filters })
42522
+ ]);
42523
+ return {
42524
+ scorer: scorerId,
42525
+ avg: avg.value ?? 0,
42526
+ min: min.value ?? 0,
42527
+ max: max.value ?? 0,
42528
+ count: count.value ?? 0
42529
+ };
42530
+ })
42439
42531
  );
42440
- const startMs = timestamp.start.getTime();
42441
- const endMs = timestamp.end.getTime();
42442
- const allScores = [];
42443
- for (let i = 0; i < scorerIds.length; i++) {
42444
- const scores = allResults[i]?.scores ?? [];
42445
- for (const s of scores) {
42446
- const ts = new Date(s.createdAt).getTime();
42447
- if (ts >= startMs && ts <= endMs) {
42448
- allScores.push({
42449
- scorerId: scorerIds[i],
42450
- score: s.score,
42451
- createdAt: s.createdAt
42452
- });
42453
- }
42454
- }
42455
- }
42456
- if (allScores.length === 0) {
42457
- return { summaryData: [], overTimeData: [], scorerNames: [], avgScore: null };
42458
- }
42459
- const byScorer = /* @__PURE__ */ new Map();
42460
- for (const s of allScores) {
42461
- if (!byScorer.has(s.scorerId)) byScorer.set(s.scorerId, []);
42462
- byScorer.get(s.scorerId).push(s.score);
42463
- }
42464
- const summaryData = Array.from(byScorer.entries()).map(([scorer, vals]) => ({
42465
- scorer,
42466
- avg: vals.reduce((a, b) => a + b, 0) / vals.length,
42467
- min: Math.min(...vals),
42468
- max: Math.max(...vals),
42469
- count: vals.length
42470
- }));
42532
+ const summaryData = summaryResults.filter((s) => s.count > 0);
42471
42533
  const scorerNames = summaryData.map((s) => s.scorer);
42472
- const avgScore = summaryData.reduce((s, d) => s + d.avg, 0) / summaryData.length;
42473
- const bucketMap = /* @__PURE__ */ new Map();
42474
- for (const s of allScores) {
42475
- const ts = new Date(s.createdAt);
42476
- const bucket = Math.floor(ts.getTime() / 36e5) * 36e5;
42477
- if (!bucketMap.has(bucket)) bucketMap.set(bucket, /* @__PURE__ */ new Map());
42478
- const scorerMap = bucketMap.get(bucket);
42479
- if (!scorerMap.has(s.scorerId)) scorerMap.set(s.scorerId, []);
42480
- scorerMap.get(s.scorerId).push(s.score);
42534
+ if (summaryData.length === 0) {
42535
+ return { summaryData: [], overTimeData: [], scorerNames: [], avgScore: null };
42481
42536
  }
42482
- const overTimeData = Array.from(bucketMap.entries()).sort(([a], [b]) => a - b).map(([bucket, scorerMap]) => {
42483
- const point = {
42484
- time: new Date(bucket).toLocaleTimeString("en-US", {
42485
- hour: "2-digit",
42486
- minute: "2-digit",
42487
- hour12: false
42537
+ const totalWeighted = summaryData.reduce((s, d) => s + d.avg * d.count, 0);
42538
+ const totalCount = summaryData.reduce((s, d) => s + d.count, 0);
42539
+ const avgScore = totalCount ? Math.round(totalWeighted / totalCount * 100) / 100 : 0;
42540
+ const interval = "1h";
42541
+ const timeSeriesResults = await Promise.all(
42542
+ scorerNames.map(
42543
+ (scorerId) => client.getScoreTimeSeries({
42544
+ scorerId,
42545
+ interval,
42546
+ aggregation: "avg",
42547
+ filters
42488
42548
  })
42489
- };
42490
- for (const name of scorerNames) {
42491
- const vals = scorerMap.get(name);
42492
- if (vals && vals.length > 0) {
42493
- point[name] = +(vals.reduce((a, b) => a + b, 0) / vals.length).toFixed(2);
42549
+ )
42550
+ );
42551
+ const bucketMap = /* @__PURE__ */ new Map();
42552
+ const rangeSpansDays = timestamp.end.toDateString() !== timestamp.start.toDateString();
42553
+ for (let i = 0; i < scorerNames.length; i++) {
42554
+ const scorerId = scorerNames[i];
42555
+ const series = timeSeriesResults[i]?.series ?? [];
42556
+ for (const s of series) {
42557
+ for (const point of s.points) {
42558
+ const ts = new Date(point.timestamp);
42559
+ const key = ts.toISOString();
42560
+ if (!bucketMap.has(key)) {
42561
+ bucketMap.set(key, {
42562
+ time: rangeSpansDays ? ts.toLocaleString("en-US", {
42563
+ month: "short",
42564
+ day: "numeric",
42565
+ hour: "2-digit",
42566
+ minute: "2-digit",
42567
+ hour12: false
42568
+ }) : ts.toLocaleTimeString("en-US", {
42569
+ hour: "2-digit",
42570
+ minute: "2-digit",
42571
+ hour12: false
42572
+ })
42573
+ });
42574
+ }
42575
+ bucketMap.get(key)[scorerId] = +point.value.toFixed(2);
42494
42576
  }
42495
42577
  }
42496
- return point;
42497
- });
42578
+ }
42579
+ const overTimeData = Array.from(bucketMap.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, point]) => point);
42498
42580
  return {
42499
42581
  summaryData,
42500
42582
  overTimeData,
42501
42583
  scorerNames,
42502
- avgScore: Math.round(avgScore * 100) / 100
42584
+ avgScore
42503
42585
  };
42504
42586
  }
42505
42587
  });
@@ -42544,7 +42626,7 @@ function ScoresCard() {
42544
42626
  /* @__PURE__ */ jsx(Tab, { value: "over-time", children: "Over Time" }),
42545
42627
  /* @__PURE__ */ jsx(Tab, { value: "summary", children: "Summary" })
42546
42628
  ] }),
42547
- /* @__PURE__ */ jsx(TabContent, { value: "over-time", children: data.overTimeData.length > 0 ? /* @__PURE__ */ jsx(MetricsLineChart, { data: data.overTimeData, series, yDomain: [0, 1] }) : /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No time series data yet" }) }),
42629
+ /* @__PURE__ */ jsx(TabContent, { value: "over-time", className: "pb-0", children: data.overTimeData.length > 0 ? /* @__PURE__ */ jsx(MetricsLineChart, { data: data.overTimeData, series, yDomain: [0, 1] }) : /* @__PURE__ */ jsx(MetricsCard.NoData, { message: "No time series data yet" }) }),
42548
42630
  /* @__PURE__ */ jsx(TabContent, { value: "summary", children: /* @__PURE__ */ jsx(
42549
42631
  MetricsDataTable,
42550
42632
  {
@@ -42682,7 +42764,7 @@ function HorizontalBars({
42682
42764
  "div",
42683
42765
  {
42684
42766
  className: cn(
42685
- "absolute inset-y-0",
42767
+ "absolute inset-y-0 opacity-40 dark:opacity-100",
42686
42768
  si === 0 && "rounded-l",
42687
42769
  isLastWithValue && "rounded-r"
42688
42770
  ),
@@ -42698,7 +42780,7 @@ function HorizontalBars({
42698
42780
  return /* @__PURE__ */ jsx(
42699
42781
  "div",
42700
42782
  {
42701
- className: "absolute inset-y-0 left-0 rounded",
42783
+ className: "absolute inset-y-0 left-0 rounded opacity-40 dark:opacity-100",
42702
42784
  style: { width: `${pct}%`, backgroundColor: seg.color }
42703
42785
  },
42704
42786
  seg.label
@@ -43794,6 +43876,9 @@ function SpanScoreList({
43794
43876
  const score = scoresData?.scores?.find((s) => s?.id === scoreId);
43795
43877
  setSelectedScore(score);
43796
43878
  setDialogIsOpen(true);
43879
+ if (traceId) {
43880
+ navigate(`${computeTraceLink(traceId, spanId)}&tab=scores&scoreId=${encodeURIComponent(scoreId)}`);
43881
+ }
43797
43882
  };
43798
43883
  if (isLoadingScoresData) {
43799
43884
  return /* @__PURE__ */ jsx(EntryListSkeleton, { columns: traceScoresListColumns });