@mastra/playground-ui 23.0.2 → 24.0.0-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.
Files changed (85) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/index.cjs.js +4254 -13
  3. package/dist/index.cjs.js.map +1 -1
  4. package/dist/index.css +354 -84
  5. package/dist/index.es.js +4137 -16
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/src/domains/logs/components/index.d.ts +6 -0
  8. package/dist/src/domains/logs/components/log-details-view.d.ts +12 -0
  9. package/dist/src/domains/logs/components/logs-error-content.d.ts +14 -0
  10. package/dist/src/domains/logs/components/logs-layout.d.ts +19 -0
  11. package/dist/src/domains/logs/components/logs-list-view.d.ts +20 -0
  12. package/dist/src/domains/logs/components/logs-toolbar.d.ts +13 -0
  13. package/dist/src/domains/logs/components/no-logs-info.d.ts +1 -0
  14. package/dist/src/domains/logs/hooks/index.d.ts +4 -0
  15. package/dist/src/domains/logs/hooks/use-logs-filter-persistence.d.ts +22 -0
  16. package/dist/src/domains/logs/hooks/use-logs-list-navigation.d.ts +22 -0
  17. package/dist/src/domains/logs/hooks/use-logs-url-state.d.ts +38 -0
  18. package/dist/src/domains/logs/hooks/use-logs.d.ts +1271 -0
  19. package/dist/src/domains/logs/index.d.ts +4 -0
  20. package/dist/src/domains/logs/log-filters.d.ts +109 -0
  21. package/dist/src/domains/logs/types.d.ts +35 -0
  22. package/dist/src/domains/metrics/components/bar-list.d.ts +21 -0
  23. package/dist/src/domains/metrics/components/date-range-selector.d.ts +1 -0
  24. package/dist/src/domains/metrics/components/index.d.ts +9 -0
  25. package/dist/src/domains/metrics/components/kpi-card-view.d.ts +9 -0
  26. package/dist/src/domains/metrics/components/latency-card-view.d.ts +11 -0
  27. package/dist/src/domains/metrics/components/metrics-utils.d.ts +15 -0
  28. package/dist/src/domains/metrics/components/model-usage-cost-card-view.d.ts +7 -0
  29. package/dist/src/domains/metrics/components/scores-card-view.d.ts +12 -0
  30. package/dist/src/domains/metrics/components/token-usage-by-agent-card-view.d.ts +7 -0
  31. package/dist/src/domains/metrics/components/traces-volume-card-view.d.ts +11 -0
  32. package/dist/src/domains/metrics/hooks/index.d.ts +12 -0
  33. package/dist/src/domains/metrics/hooks/use-agent-runs-kpi-metrics.d.ts +10 -0
  34. package/dist/src/domains/metrics/hooks/use-avg-score-kpi-metrics.d.ts +10 -0
  35. package/dist/src/domains/metrics/hooks/use-latency-metrics.d.ts +11 -0
  36. package/dist/src/domains/metrics/hooks/use-metrics-filters.d.ts +9 -0
  37. package/dist/src/domains/metrics/hooks/use-metrics.d.ts +43 -0
  38. package/dist/src/domains/metrics/hooks/use-model-cost-kpi-metrics.d.ts +7 -0
  39. package/dist/src/domains/metrics/hooks/use-model-usage-cost-metrics.d.ts +10 -0
  40. package/dist/src/domains/metrics/hooks/use-scores-metrics.d.ts +22 -0
  41. package/dist/src/domains/metrics/hooks/use-token-usage-by-agent-metrics.d.ts +9 -0
  42. package/dist/src/domains/metrics/hooks/use-total-tokens-kpi-metrics.d.ts +6 -0
  43. package/dist/src/domains/metrics/hooks/use-trace-volume-metrics.d.ts +10 -0
  44. package/dist/src/domains/metrics/index.d.ts +2 -0
  45. package/dist/src/domains/traces/components/format-hierarchical-spans.d.ts +12 -0
  46. package/dist/src/domains/traces/components/index.d.ts +18 -0
  47. package/dist/src/domains/traces/components/shared.d.ts +3 -0
  48. package/dist/src/domains/traces/components/span-data-panel-view.d.ts +26 -0
  49. package/dist/src/domains/traces/components/span-details-view.d.ts +14 -0
  50. package/dist/src/domains/traces/components/span-token-usage.d.ts +22 -0
  51. package/dist/src/domains/traces/components/timeline-expand-col.d.ts +12 -0
  52. package/dist/src/domains/traces/components/timeline-name-col.d.ts +15 -0
  53. package/dist/src/domains/traces/components/timeline-structure-sign.d.ts +5 -0
  54. package/dist/src/domains/traces/components/timeline-timing-col.d.ts +12 -0
  55. package/dist/src/domains/traces/components/trace-data-panel-view.d.ts +28 -0
  56. package/dist/src/domains/traces/components/trace-details-view.d.ts +18 -0
  57. package/dist/src/domains/traces/components/trace-keys-and-values.d.ts +16 -0
  58. package/dist/src/domains/traces/components/trace-timeline-span.d.ts +18 -0
  59. package/dist/src/domains/traces/components/trace-timeline.d.ts +15 -0
  60. package/dist/src/domains/traces/components/traces-error-content.d.ts +16 -0
  61. package/dist/src/domains/traces/components/traces-layout.d.ts +18 -0
  62. package/dist/src/domains/traces/components/traces-list-view.d.ts +39 -0
  63. package/dist/src/domains/traces/components/traces-toolbar.d.ts +19 -0
  64. package/dist/src/domains/traces/hooks/get-all-span-ids.d.ts +3 -0
  65. package/dist/src/domains/traces/hooks/index.d.ts +13 -0
  66. package/dist/src/domains/traces/hooks/use-entity-names.d.ts +7 -0
  67. package/dist/src/domains/traces/hooks/use-environments.d.ts +1 -0
  68. package/dist/src/domains/traces/hooks/use-service-names.d.ts +1 -0
  69. package/dist/src/domains/traces/hooks/use-span-detail.d.ts +46 -0
  70. package/dist/src/domains/traces/hooks/use-tags.d.ts +1 -0
  71. package/dist/src/domains/traces/hooks/use-trace-filter-persistence.d.ts +31 -0
  72. package/dist/src/domains/traces/hooks/use-trace-light-spans.d.ts +19 -0
  73. package/dist/src/domains/traces/hooks/use-trace-list-navigation.d.ts +12 -0
  74. package/dist/src/domains/traces/hooks/use-trace-span-navigation.d.ts +10 -0
  75. package/dist/src/domains/traces/hooks/use-trace-spans.d.ts +47 -0
  76. package/dist/src/domains/traces/hooks/use-trace-url-state.d.ts +53 -0
  77. package/dist/src/domains/traces/hooks/use-traces.d.ts +1549 -0
  78. package/dist/src/domains/traces/index.d.ts +8 -0
  79. package/dist/src/domains/traces/trace-filters.d.ts +121 -0
  80. package/dist/src/domains/traces/types.d.ts +35 -0
  81. package/dist/src/domains/traces/utils/group-traces-by-thread.d.ts +20 -0
  82. package/dist/src/domains/traces/utils/index.d.ts +2 -0
  83. package/dist/src/domains/traces/utils/span-utils.d.ts +15 -0
  84. package/dist/src/index.d.ts +3 -0
  85. package/package.json +12 -9
package/dist/index.cjs.js CHANGED
@@ -50,6 +50,8 @@ const isToday = require('date-fns/isToday');
50
50
  const search = require('@codemirror/search');
51
51
  const recharts = require('recharts');
52
52
  const reactResizablePanels = require('react-resizable-panels');
53
+ const reactQuery = require('@tanstack/react-query');
54
+ const observability = require('@mastra/core/observability');
53
55
 
54
56
  function _interopNamespaceDefault(e) {
55
57
  const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
@@ -12062,16 +12064,16 @@ function DataListSkeleton({ columns = "auto 1fr auto auto", numberOfRows = 3 })
12062
12064
  )) });
12063
12065
  }
12064
12066
 
12065
- function toDate$2(value) {
12067
+ function toDate$3(value) {
12066
12068
  const date = value instanceof Date ? value : new Date(value);
12067
12069
  return isNaN(date.getTime()) ? null : date;
12068
12070
  }
12069
12071
  function ScoresDataListDateCell({ timestamp }) {
12070
- const date = toDate$2(timestamp);
12072
+ const date = toDate$3(timestamp);
12071
12073
  return /* @__PURE__ */ jsxRuntime.jsx(DataListCell, { height: "compact", className: "text-ui-smd text-neutral2", children: date ? dateFns.isToday(date) ? "Today" : dateFns.format(date, "MMM dd") : "-" });
12072
12074
  }
12073
12075
  function ScoresDataListTimeCell({ timestamp }) {
12074
- const date = toDate$2(timestamp);
12076
+ const date = toDate$3(timestamp);
12075
12077
  return /* @__PURE__ */ jsxRuntime.jsx(DataListCell, { height: "compact", className: "text-ui-smd text-neutral3", children: date ? dateFns.format(date, "h:mm:ss aaa") : "-" });
12076
12078
  }
12077
12079
  function ScoresDataListInputCell({ input }) {
@@ -12101,7 +12103,7 @@ const ScoresDataList = Object.assign(ScoresDataListRoot, {
12101
12103
  ScoreCell: ScoresDataListScoreCell
12102
12104
  });
12103
12105
 
12104
- function toDate$1(value) {
12106
+ function toDate$2(value) {
12105
12107
  const date = value instanceof Date ? value : new Date(value);
12106
12108
  return isNaN(date.getTime()) ? null : date;
12107
12109
  }
@@ -12113,11 +12115,11 @@ function TracesDataListIdCell({ traceId }) {
12113
12115
  return /* @__PURE__ */ jsxRuntime.jsx(DataListCell, { height: "compact", className: "text-ui-smd font-mono text-neutral3", children: getShortId(traceId) });
12114
12116
  }
12115
12117
  function TracesDataListDateCell({ timestamp }) {
12116
- const date = toDate$1(timestamp);
12118
+ const date = toDate$2(timestamp);
12117
12119
  return /* @__PURE__ */ jsxRuntime.jsx(DataListCell, { height: "compact", className: "text-ui-smd text-neutral2", children: date ? dateFns.isToday(date) ? "Today" : dateFns.format(date, "MMM dd") : "-" });
12118
12120
  }
12119
12121
  function TracesDataListTimeCell({ timestamp }) {
12120
- const date = toDate$1(timestamp);
12122
+ const date = toDate$2(timestamp);
12121
12123
  return /* @__PURE__ */ jsxRuntime.jsx(DataListCell, { height: "compact", className: "text-ui-smd font-mono text-neutral3 flex", children: date ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
12122
12124
  dateFns.format(date, "HH:mm:ss"),
12123
12125
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-neutral2", children: [
@@ -12398,7 +12400,7 @@ function EntityListSkeleton({ columns, numberOfRows = 3 }) {
12398
12400
  )) });
12399
12401
  }
12400
12402
 
12401
- function toDate(value) {
12403
+ function toDate$1(value) {
12402
12404
  const date = value instanceof Date ? value : new Date(value);
12403
12405
  return isNaN(date.getTime()) ? null : date;
12404
12406
  }
@@ -12414,11 +12416,11 @@ function LogsDataListLevelCell({ level }) {
12414
12416
  return /* @__PURE__ */ jsxRuntime.jsx(DataListCell, { height: "compact", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "uppercase text-ui-sm font-semibold", style: { color: config.color }, children: config.label }) });
12415
12417
  }
12416
12418
  function LogsDataListDateCell({ timestamp }) {
12417
- const date = toDate(timestamp);
12419
+ const date = toDate$1(timestamp);
12418
12420
  return /* @__PURE__ */ jsxRuntime.jsx(DataListCell, { height: "compact", className: "text-ui-smd text-neutral2", children: date ? dateFns.isToday(date) ? "Today" : dateFns.format(date, "MMM dd") : "-" });
12419
12421
  }
12420
12422
  function LogsDataListTimeCell({ timestamp }) {
12421
- const date = toDate(timestamp);
12423
+ const date = toDate$1(timestamp);
12422
12424
  return /* @__PURE__ */ jsxRuntime.jsx(DataListCell, { height: "compact", className: "text-ui-smd font-mono text-neutral3 flex", children: date ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
12423
12425
  dateFns.format(date, "HH:mm:ss"),
12424
12426
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-neutral2", children: [
@@ -13543,7 +13545,7 @@ const DataPanel = Object.assign(DataPanelRoot, {
13543
13545
  CodeSection: DataCodeSection
13544
13546
  });
13545
13547
 
13546
- const DATE_PRESETS = [
13548
+ const DATE_PRESETS$1 = [
13547
13549
  { value: "all", label: "All" },
13548
13550
  { value: "last-24h", label: "Last 24 hours", ms: 24 * 60 * 60 * 1e3 },
13549
13551
  { value: "last-3d", label: "Last 3 days", ms: 3 * 24 * 60 * 60 * 1e3 },
@@ -13567,7 +13569,7 @@ function DateTimeRangePicker({
13567
13569
  presets,
13568
13570
  size = "md"
13569
13571
  }) {
13570
- const visiblePresets = presets ? DATE_PRESETS.filter((p) => presets.includes(p.value)) : DATE_PRESETS;
13572
+ const visiblePresets = presets ? DATE_PRESETS$1.filter((p) => presets.includes(p.value)) : DATE_PRESETS$1;
13571
13573
  const fallbackPreset = visiblePresets.find((p) => p.value !== "custom")?.value ?? "all";
13572
13574
  const [customRangeOpen, setCustomRangeOpen] = React.useState(false);
13573
13575
  const [draftDateFrom, setDraftDateFrom] = React.useState(dateFrom);
@@ -13575,7 +13577,7 @@ function DateTimeRangePicker({
13575
13577
  const [draftTimeFrom, setDraftTimeFrom] = React.useState("12:00 AM");
13576
13578
  const [draftTimeTo, setDraftTimeTo] = React.useState("11:59 PM");
13577
13579
  const [customRangeError, setCustomRangeError] = React.useState();
13578
- const datePresetLabel = DATE_PRESETS.find((p) => p.value === preset)?.label ?? "All";
13580
+ const datePresetLabel = DATE_PRESETS$1.find((p) => p.value === preset)?.label ?? "All";
13579
13581
  const handlePresetSelect = (value) => {
13580
13582
  onPresetChange?.(value);
13581
13583
  if (value === "custom") {
@@ -13586,7 +13588,7 @@ function DateTimeRangePicker({
13586
13588
  setCustomRangeOpen(true);
13587
13589
  return;
13588
13590
  }
13589
- const entry = DATE_PRESETS.find((p) => p.value === value);
13591
+ const entry = DATE_PRESETS$1.find((p) => p.value === value);
13590
13592
  if (entry?.ms) {
13591
13593
  onDateChange?.(new Date(Date.now() - entry.ms), "from");
13592
13594
  onDateChange?.(void 0, "to");
@@ -15004,6 +15006,4125 @@ function generateDefaultValues(schema) {
15004
15006
  return generateObjectDefaults(schema.properties, 0);
15005
15007
  }
15006
15008
 
15009
+ const DATE_PRESETS = [
15010
+ { label: "Last 24 hours", value: "24h" },
15011
+ { label: "Last 3 days", value: "3d" },
15012
+ { label: "Last 7 days", value: "7d" },
15013
+ { label: "Last 14 days", value: "14d" },
15014
+ { label: "Last 30 days", value: "30d" }
15015
+ ];
15016
+ const VALID_PRESETS = new Set(DATE_PRESETS.map((p) => p.value));
15017
+ function isValidPreset(value) {
15018
+ return typeof value === "string" && (VALID_PRESETS.has(value) || value === "custom");
15019
+ }
15020
+ const MetricsContext = React.createContext({
15021
+ datePreset: "24h",
15022
+ setDatePreset: () => {
15023
+ },
15024
+ customRange: void 0,
15025
+ setCustomRange: () => {
15026
+ },
15027
+ dateRangeLabel: "Last 24 hours"
15028
+ });
15029
+ function useMetrics() {
15030
+ return React.useContext(MetricsContext);
15031
+ }
15032
+ function getDateRangeLabel(preset, customRange) {
15033
+ if (preset !== "custom") {
15034
+ return DATE_PRESETS.find((p) => p.value === preset).label;
15035
+ }
15036
+ if (customRange?.from) {
15037
+ if (customRange.to) {
15038
+ return `${dateFns.format(customRange.from, "MMM d, yyyy")} – ${dateFns.format(customRange.to, "MMM d, yyyy")}`;
15039
+ }
15040
+ return dateFns.format(customRange.from, "MMM d, yyyy");
15041
+ }
15042
+ return "Custom range";
15043
+ }
15044
+ function MetricsProvider({
15045
+ children,
15046
+ initialPreset,
15047
+ onPresetChange
15048
+ }) {
15049
+ const [datePreset, setDatePresetState] = React.useState(initialPreset ?? "24h");
15050
+ const [customRange, setCustomRange] = React.useState(void 0);
15051
+ const dateRangeLabel = getDateRangeLabel(datePreset, customRange);
15052
+ React.useEffect(() => {
15053
+ if (initialPreset && initialPreset !== datePreset) {
15054
+ setDatePresetState(initialPreset);
15055
+ }
15056
+ }, [initialPreset]);
15057
+ const setDatePreset = React.useCallback(
15058
+ (v) => {
15059
+ setDatePresetState(v);
15060
+ onPresetChange?.(v);
15061
+ },
15062
+ [onPresetChange]
15063
+ );
15064
+ return /* @__PURE__ */ jsxRuntime.jsx(
15065
+ MetricsContext.Provider,
15066
+ {
15067
+ value: {
15068
+ datePreset,
15069
+ setDatePreset,
15070
+ customRange,
15071
+ setCustomRange,
15072
+ dateRangeLabel
15073
+ },
15074
+ children
15075
+ }
15076
+ );
15077
+ }
15078
+
15079
+ function DateRangeSelector() {
15080
+ const { datePreset, setDatePreset } = useMetrics();
15081
+ return /* @__PURE__ */ jsxRuntime.jsx(
15082
+ SelectFieldBlock,
15083
+ {
15084
+ name: "date-range",
15085
+ labelIsHidden: true,
15086
+ value: datePreset,
15087
+ options: DATE_PRESETS.map((p) => ({ label: p.label, value: p.value })),
15088
+ onValueChange: (value) => {
15089
+ if (isValidPreset(value)) setDatePreset(value);
15090
+ }
15091
+ }
15092
+ );
15093
+ }
15094
+
15095
+ function formatCompact(n) {
15096
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
15097
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
15098
+ return n.toLocaleString();
15099
+ }
15100
+ function formatCost(value, unit) {
15101
+ if (unit?.toLowerCase() === "usd" || !unit) {
15102
+ return `$${value < 0.01 && value > 0 ? value.toFixed(4) : value.toFixed(2)}`;
15103
+ }
15104
+ return `${value.toFixed(4)} ${unit}`;
15105
+ }
15106
+ const CHART_COLORS = {
15107
+ green: "#22c55e",
15108
+ orange: "#fb923c",
15109
+ pink: "#f472b6",
15110
+ purple: "#8b5cf6",
15111
+ blue: "#4f83f1",
15112
+ blueDark: "#2b5cd9",
15113
+ blueLight: "#6b8fe5",
15114
+ red: "#f87171",
15115
+ greenDark: "#15613a",
15116
+ redDark: "#991b1b",
15117
+ yellow: "#facc15"
15118
+ };
15119
+
15120
+ function BarListContent({
15121
+ data,
15122
+ maxVal,
15123
+ fmt,
15124
+ color,
15125
+ valueLabel,
15126
+ legend
15127
+ }) {
15128
+ const sorted = [...data].sort((a, b) => b.value - a.value);
15129
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
15130
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mb-2", children: [
15131
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center gap-4", children: legend?.map((l) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
15132
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "size-2 rounded-full", style: { backgroundColor: l.color } }),
15133
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-icon2", children: l.label })
15134
+ ] }, l.label)) }),
15135
+ valueLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs text-icon2", children: valueLabel })
15136
+ ] }),
15137
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2.5", children: sorted.map((d) => {
15138
+ const pct = Math.min(Math.max(maxVal > 0 ? d.value / maxVal * 100 : 0, 0), 100);
15139
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group flex items-center gap-3", children: [
15140
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 h-7", children: [
15141
+ /* @__PURE__ */ jsxRuntime.jsx(
15142
+ "div",
15143
+ {
15144
+ className: "absolute inset-y-0 left-0 rounded",
15145
+ style: { width: `${pct}%`, backgroundColor: color }
15146
+ }
15147
+ ),
15148
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-y-0 left-2 flex items-center text-xs text-white whitespace-nowrap", children: d.name })
15149
+ ] }),
15150
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs font-mono text-icon6 tabular-nums", children: fmt(d.value) })
15151
+ ] }, d.name);
15152
+ }) })
15153
+ ] });
15154
+ }
15155
+ function StackedRunsBars({ data }) {
15156
+ const sorted = [...data].sort((a, b) => b.completed + b.errors - (a.completed + a.errors));
15157
+ const maxTotal = Math.max(...sorted.map((d) => d.completed + d.errors));
15158
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
15159
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mb-2", children: [
15160
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex items-center gap-4", children: [
15161
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
15162
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "size-2 rounded-full", style: { backgroundColor: CHART_COLORS.blue } }),
15163
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-icon2", children: "Completed" })
15164
+ ] }),
15165
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
15166
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "size-2 rounded-full", style: { backgroundColor: CHART_COLORS.red } }),
15167
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-icon2", children: "Errors" })
15168
+ ] })
15169
+ ] }),
15170
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-xs text-icon2", children: "Total (Success)" })
15171
+ ] }),
15172
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2.5", children: sorted.map((d) => {
15173
+ const total = d.completed + d.errors;
15174
+ const successPct = total > 0 ? (d.completed / total * 100).toFixed(1) : "0.0";
15175
+ const completedWidth = Math.min(Math.max(maxTotal > 0 ? d.completed / maxTotal * 100 : 0, 0), 100);
15176
+ const errorsWidth = Math.min(Math.max(maxTotal > 0 ? d.errors / maxTotal * 100 : 0, 0), 100);
15177
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group flex items-center gap-3", children: [
15178
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 h-7", children: [
15179
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
15180
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
15181
+ "div",
15182
+ {
15183
+ role: "img",
15184
+ "aria-label": `${d.completed.toLocaleString()} completed`,
15185
+ tabIndex: 0,
15186
+ className: "absolute inset-y-0 left-0 rounded-l cursor-default",
15187
+ style: { width: `${completedWidth}%`, backgroundColor: CHART_COLORS.blue }
15188
+ }
15189
+ ) }),
15190
+ /* @__PURE__ */ jsxRuntime.jsxs(TooltipContent, { side: "top", className: "font-mono", children: [
15191
+ d.completed.toLocaleString(),
15192
+ " completed"
15193
+ ] })
15194
+ ] }),
15195
+ /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
15196
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
15197
+ "div",
15198
+ {
15199
+ role: "img",
15200
+ "aria-label": `${d.errors.toLocaleString()} errors`,
15201
+ tabIndex: 0,
15202
+ className: "absolute inset-y-0 rounded-r cursor-default",
15203
+ style: {
15204
+ left: `${completedWidth}%`,
15205
+ width: `${errorsWidth}%`,
15206
+ backgroundColor: CHART_COLORS.red
15207
+ }
15208
+ }
15209
+ ) }),
15210
+ /* @__PURE__ */ jsxRuntime.jsxs(TooltipContent, { side: "top", className: "font-mono", children: [
15211
+ d.errors.toLocaleString(),
15212
+ " errors"
15213
+ ] })
15214
+ ] }),
15215
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-y-0 left-2 flex items-center text-xs text-white whitespace-nowrap pointer-events-none", children: d.name })
15216
+ ] }),
15217
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "shrink-0 text-xs font-mono text-icon6 tabular-nums", children: [
15218
+ total.toLocaleString(),
15219
+ " (",
15220
+ successPct,
15221
+ "%)"
15222
+ ] })
15223
+ ] }, d.name);
15224
+ }) })
15225
+ ] });
15226
+ }
15227
+
15228
+ function KpiCardView({ label, value, prevValue, changePct, isLoading, isError }) {
15229
+ const hasData = value != null;
15230
+ return /* @__PURE__ */ jsxRuntime.jsxs(MetricsKpiCard, { children: [
15231
+ /* @__PURE__ */ jsxRuntime.jsx(MetricsKpiCard.Label, { children: label }),
15232
+ /* @__PURE__ */ jsxRuntime.jsx(MetricsKpiCard.Value, { className: hasData ? void 0 : "invisible", children: hasData ? value : "—" }),
15233
+ isError ? /* @__PURE__ */ jsxRuntime.jsx(MetricsKpiCard.Error, {}) : isLoading ? /* @__PURE__ */ jsxRuntime.jsx(MetricsKpiCard.Loading, {}) : hasData ? changePct != null ? /* @__PURE__ */ jsxRuntime.jsx(MetricsKpiCard.Change, { changePct, prevValue }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsKpiCard.NoChange, {}) : /* @__PURE__ */ jsxRuntime.jsx(MetricsKpiCard.NoData, {})
15234
+ ] });
15235
+ }
15236
+
15237
+ const latencySeries = [
15238
+ {
15239
+ dataKey: "p50",
15240
+ label: "p50",
15241
+ color: CHART_COLORS.blue,
15242
+ aggregate: (data) => ({
15243
+ value: data.length > 0 ? `${Math.round(data.reduce((s, d) => s + d.p50, 0) / data.length)}` : "0",
15244
+ suffix: "avg ms"
15245
+ })
15246
+ },
15247
+ {
15248
+ dataKey: "p95",
15249
+ label: "p95",
15250
+ color: CHART_COLORS.yellow,
15251
+ aggregate: (data) => ({
15252
+ value: data.length > 0 ? `${Math.round(data.reduce((s, d) => s + d.p95, 0) / data.length)}` : "0",
15253
+ suffix: "avg ms"
15254
+ })
15255
+ }
15256
+ ];
15257
+ function LatencyChart({ data }) {
15258
+ if (data.length === 0) {
15259
+ return /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No latency data yet" });
15260
+ }
15261
+ return /* @__PURE__ */ jsxRuntime.jsx(MetricsLineChart, { data, series: latencySeries });
15262
+ }
15263
+ function LatencyCardView({ data, isLoading, isError }) {
15264
+ const hasData = !!data && (data.agentData.length > 0 || data.workflowData.length > 0 || data.toolData.length > 0);
15265
+ const p50Values = data ? Object.values(data).filter(Array.isArray).flat().map((d) => d.p50).filter((v) => typeof v === "number") : [];
15266
+ const avgP50 = p50Values.length > 0 ? `${Math.round(p50Values.reduce((s, v) => s + v, 0) / p50Values.length)}ms` : "—";
15267
+ return /* @__PURE__ */ jsxRuntime.jsxs(MetricsCard, { children: [
15268
+ /* @__PURE__ */ jsxRuntime.jsxs(MetricsCard.TopBar, { children: [
15269
+ /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.TitleAndDescription, { title: "Latency", description: "Hourly p50 and p95 latency." }),
15270
+ hasData && /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Summary, { value: avgP50, label: "Avg p50" })
15271
+ ] }),
15272
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Loading, {}) : isError ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Error, { message: "Failed to load latency data" }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Content, { children: !hasData ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No latency data yet" }) : /* @__PURE__ */ jsxRuntime.jsxs(
15273
+ Tabs,
15274
+ {
15275
+ defaultTab: data.agentData.length > 0 ? "agents" : data.workflowData.length > 0 ? "workflows" : data.toolData.length > 0 ? "tools" : "agents",
15276
+ className: "overflow-visible",
15277
+ children: [
15278
+ /* @__PURE__ */ jsxRuntime.jsxs(TabList, { children: [
15279
+ /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "agents", children: "Agents" }),
15280
+ /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "workflows", children: "Workflows" }),
15281
+ /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "tools", children: "Tools" })
15282
+ ] }),
15283
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "agents", children: /* @__PURE__ */ jsxRuntime.jsx(LatencyChart, { data: data.agentData }) }),
15284
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "workflows", children: /* @__PURE__ */ jsxRuntime.jsx(LatencyChart, { data: data.workflowData }) }),
15285
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "tools", children: /* @__PURE__ */ jsxRuntime.jsx(LatencyChart, { data: data.toolData }) })
15286
+ ]
15287
+ }
15288
+ ) })
15289
+ ] });
15290
+ }
15291
+
15292
+ function ModelUsageCostCardView({ rows, isLoading, isError }) {
15293
+ const hasData = !!rows && rows.length > 0;
15294
+ return /* @__PURE__ */ jsxRuntime.jsxs(MetricsCard, { children: [
15295
+ /* @__PURE__ */ jsxRuntime.jsxs(MetricsCard.TopBar, { children: [
15296
+ /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.TitleAndDescription, { title: "Model Usage & Cost", description: "Token consumption by model." }),
15297
+ hasData && (() => {
15298
+ const totalCost = rows.reduce((sum, r) => sum + (r.cost ?? 0), 0);
15299
+ const units = new Set(rows.filter((r) => r.cost != null && r.costUnit).map((r) => r.costUnit));
15300
+ let value;
15301
+ if (units.size === 0) {
15302
+ value = totalCost > 0 ? formatCost(totalCost) : "—";
15303
+ } else if (units.size === 1) {
15304
+ value = totalCost > 0 ? formatCost(totalCost, [...units][0]) : "—";
15305
+ } else {
15306
+ value = "Mixed";
15307
+ }
15308
+ return /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Summary, { value, label: "Total cost" });
15309
+ })()
15310
+ ] }),
15311
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Loading, {}) : isError ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Error, { message: "Failed to load model usage data" }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Content, { children: !hasData ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No model usage data yet" }) : /* @__PURE__ */ jsxRuntime.jsx(
15312
+ MetricsDataTable,
15313
+ {
15314
+ columns: [
15315
+ { label: "Model", value: (row) => row.model },
15316
+ { label: "Input", value: (row) => row.input },
15317
+ { label: "Output", value: (row) => row.output },
15318
+ { label: "Cache Read", value: (row) => row.cacheRead },
15319
+ { label: "Cache Write", value: (row) => row.cacheWrite },
15320
+ {
15321
+ label: "Cost",
15322
+ value: (row) => row.cost != null ? formatCost(row.cost, row.costUnit) : "—",
15323
+ highlight: true
15324
+ }
15325
+ ],
15326
+ data: rows.map((row) => ({ ...row, key: row.model }))
15327
+ }
15328
+ ) })
15329
+ ] });
15330
+ }
15331
+
15332
+ const SERIES_COLORS = [
15333
+ CHART_COLORS.green,
15334
+ CHART_COLORS.blue,
15335
+ CHART_COLORS.purple,
15336
+ CHART_COLORS.orange,
15337
+ CHART_COLORS.pink,
15338
+ CHART_COLORS.yellow
15339
+ ];
15340
+ function ScoresCardView({ data, isLoading, isError }) {
15341
+ const hasData = !!data && (data.summaryData.length > 0 || data.overTimeData.length > 0);
15342
+ const series = React.useMemo(() => {
15343
+ if (!data?.scorerNames) return [];
15344
+ return data.scorerNames.map((name, i) => ({
15345
+ dataKey: name,
15346
+ label: name,
15347
+ color: SERIES_COLORS[i % SERIES_COLORS.length],
15348
+ aggregate: (points) => ({
15349
+ value: points.length > 0 ? (points.reduce((s, d) => s + (d[name] ?? 0), 0) / points.length).toFixed(2) : "0",
15350
+ suffix: "avg"
15351
+ })
15352
+ }));
15353
+ }, [data?.scorerNames]);
15354
+ return /* @__PURE__ */ jsxRuntime.jsxs(MetricsCard, { children: [
15355
+ /* @__PURE__ */ jsxRuntime.jsxs(MetricsCard.TopBar, { children: [
15356
+ /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.TitleAndDescription, { title: "Scores", description: "Evaluation scorer performance." }),
15357
+ hasData && /* @__PURE__ */ jsxRuntime.jsx(
15358
+ MetricsCard.Summary,
15359
+ {
15360
+ value: data?.avgScore != null ? `avg ${data.avgScore}` : "—",
15361
+ label: "Across all scorers"
15362
+ }
15363
+ )
15364
+ ] }),
15365
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Loading, {}) : isError ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Error, { message: "Failed to load scores data" }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Content, { children: !hasData ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No scores data yet" }) : /* @__PURE__ */ jsxRuntime.jsxs(Tabs, { defaultTab: "over-time", className: "overflow-visible", children: [
15366
+ /* @__PURE__ */ jsxRuntime.jsxs(TabList, { children: [
15367
+ /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "over-time", children: "Over Time" }),
15368
+ /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "summary", children: "Summary" })
15369
+ ] }),
15370
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "over-time", className: "pb-0", children: data.overTimeData.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(MetricsLineChart, { data: data.overTimeData, series, yDomain: [0, 1] }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No time series data yet" }) }),
15371
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "summary", children: /* @__PURE__ */ jsxRuntime.jsx(
15372
+ MetricsDataTable,
15373
+ {
15374
+ columns: [
15375
+ { label: "Scorer", value: (row) => row.scorer },
15376
+ { label: "Avg", value: (row) => row.avg.toFixed(2), highlight: true },
15377
+ { label: "Min", value: (row) => row.min.toFixed(2) },
15378
+ { label: "Max", value: (row) => row.max.toFixed(2) },
15379
+ { label: "Count", value: (row) => row.count.toLocaleString() }
15380
+ ],
15381
+ data: data.summaryData.map((row) => ({ ...row, key: row.scorer }))
15382
+ }
15383
+ ) })
15384
+ ] }) })
15385
+ ] });
15386
+ }
15387
+
15388
+ function isTokenUsageTab(value) {
15389
+ return value === "tokens" || value === "cost";
15390
+ }
15391
+ function TokenUsageByAgentCardView({ data, isLoading, isError }) {
15392
+ const [activeTab, setActiveTab] = React.useState("tokens");
15393
+ const rows = data ?? [];
15394
+ const hasData = rows.length > 0;
15395
+ const totalTokens = rows.reduce((s, d) => s + d.total, 0);
15396
+ const costRows = rows.filter((d) => d.cost != null && d.cost > 0);
15397
+ const uniqueCostUnits = new Set(costRows.map((d) => d.costUnit ?? "usd"));
15398
+ const hasSingleCostUnit = uniqueCostUnits.size <= 1;
15399
+ const costUnit = hasSingleCostUnit ? [...uniqueCostUnits][0] ?? "usd" : null;
15400
+ const totalCost = hasSingleCostUnit ? costRows.reduce((s, d) => s + (d.cost ?? 0), 0) : 0;
15401
+ const hasCostData = hasSingleCostUnit && totalCost > 0;
15402
+ return /* @__PURE__ */ jsxRuntime.jsxs(MetricsCard, { children: [
15403
+ /* @__PURE__ */ jsxRuntime.jsxs(MetricsCard.TopBar, { children: [
15404
+ /* @__PURE__ */ jsxRuntime.jsx(
15405
+ MetricsCard.TitleAndDescription,
15406
+ {
15407
+ title: "Token Usage by Agent",
15408
+ description: "Token consumption grouped by agent."
15409
+ }
15410
+ ),
15411
+ hasData && (activeTab === "cost" && hasCostData ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Summary, { value: formatCost(totalCost, costUnit), label: "Total cost" }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Summary, { value: formatCompact(totalTokens), label: "Total tokens" }))
15412
+ ] }),
15413
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Loading, {}) : isError ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Error, { message: "Failed to load token usage data" }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Content, { children: !hasData ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No token usage data yet" }) : /* @__PURE__ */ jsxRuntime.jsxs(
15414
+ Tabs,
15415
+ {
15416
+ defaultTab: "tokens",
15417
+ value: activeTab,
15418
+ onValueChange: (v) => {
15419
+ if (isTokenUsageTab(v)) setActiveTab(v);
15420
+ },
15421
+ className: "grid grid-rows-[auto_1fr] overflow-y-auto h-full",
15422
+ children: [
15423
+ /* @__PURE__ */ jsxRuntime.jsxs(TabList, { children: [
15424
+ /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "tokens", children: "Tokens" }),
15425
+ /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "cost", children: "Cost" })
15426
+ ] }),
15427
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "tokens", children: /* @__PURE__ */ jsxRuntime.jsx(
15428
+ HorizontalBars,
15429
+ {
15430
+ data: rows.map((d) => ({ name: d.name, values: [d.input, d.output] })),
15431
+ segments: [
15432
+ { label: "Input", color: CHART_COLORS.blueDark },
15433
+ { label: "Output", color: CHART_COLORS.blue }
15434
+ ],
15435
+ maxVal: Math.max(...rows.map((d) => d.input + d.output)),
15436
+ fmt: formatCompact
15437
+ }
15438
+ ) }),
15439
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "cost", children: hasCostData ? /* @__PURE__ */ jsxRuntime.jsx(
15440
+ HorizontalBars,
15441
+ {
15442
+ data: costRows.slice().sort((a, b) => (b.cost ?? 0) - (a.cost ?? 0)).map((d) => ({ name: d.name, values: [d.cost] })),
15443
+ segments: [{ label: "Cost", color: CHART_COLORS.purple }],
15444
+ maxVal: Math.max(...costRows.map((d) => d.cost ?? 0)),
15445
+ fmt: (v) => formatCost(v, costUnit)
15446
+ }
15447
+ ) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No cost data yet" }) })
15448
+ ]
15449
+ }
15450
+ ) })
15451
+ ] });
15452
+ }
15453
+
15454
+ function VolumeBars({ data }) {
15455
+ return /* @__PURE__ */ jsxRuntime.jsx(
15456
+ HorizontalBars,
15457
+ {
15458
+ data: data.map((d) => ({ name: d.name, values: [d.completed, d.errors] })),
15459
+ segments: [
15460
+ { label: "Completed", color: CHART_COLORS.blueDark },
15461
+ { label: "Errors", color: CHART_COLORS.pink }
15462
+ ],
15463
+ maxVal: Math.max(...data.map((d) => d.completed + d.errors)),
15464
+ fmt: formatCompact
15465
+ }
15466
+ );
15467
+ }
15468
+ function TracesVolumeCardView({ data, isLoading, isError }) {
15469
+ const hasData = !!data && (data.agentData.length > 0 || data.workflowData.length > 0 || data.toolData.length > 0);
15470
+ const total = data ? [...data.agentData, ...data.workflowData, ...data.toolData].reduce((s, d) => s + d.completed + d.errors, 0) : 0;
15471
+ return /* @__PURE__ */ jsxRuntime.jsxs(MetricsCard, { children: [
15472
+ /* @__PURE__ */ jsxRuntime.jsxs(MetricsCard.TopBar, { children: [
15473
+ /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.TitleAndDescription, { title: "Trace Volume", description: "Runs and call counts." }),
15474
+ hasData && /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Summary, { value: formatCompact(total), label: "Total runs" })
15475
+ ] }),
15476
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Loading, {}) : isError ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Error, { message: "Failed to load trace volume data" }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.Content, { children: !hasData ? /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No trace volume data yet" }) : /* @__PURE__ */ jsxRuntime.jsxs(Tabs, { defaultTab: "agents", className: "grid grid-rows-[auto_1fr] overflow-y-auto h-full", children: [
15477
+ /* @__PURE__ */ jsxRuntime.jsxs(TabList, { children: [
15478
+ /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "agents", children: "Agents" }),
15479
+ /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "workflows", children: "Workflows" }),
15480
+ /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "tools", children: "Tools" })
15481
+ ] }),
15482
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "agents", children: data.agentData.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(VolumeBars, { data: data.agentData }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No agent data yet" }) }),
15483
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "workflows", children: data.workflowData.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(VolumeBars, { data: data.workflowData }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No workflow data yet" }) }),
15484
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "tools", children: data.toolData.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(VolumeBars, { data: data.toolData }) : /* @__PURE__ */ jsxRuntime.jsx(MetricsCard.NoData, { message: "No tool data yet" }) })
15485
+ ] }) })
15486
+ ] });
15487
+ }
15488
+
15489
+ const PRESET_MS$2 = {
15490
+ "24h": 24 * 60 * 60 * 1e3,
15491
+ "3d": 3 * 24 * 60 * 60 * 1e3,
15492
+ "7d": 7 * 24 * 60 * 60 * 1e3,
15493
+ "14d": 14 * 24 * 60 * 60 * 1e3,
15494
+ "30d": 30 * 24 * 60 * 60 * 1e3
15495
+ };
15496
+ function buildTimestamp(preset, customRange) {
15497
+ const now = /* @__PURE__ */ new Date();
15498
+ if (preset !== "custom") {
15499
+ const ms = PRESET_MS$2[preset] ?? PRESET_MS$2["24h"];
15500
+ return { start: new Date(now.getTime() - ms), end: now };
15501
+ }
15502
+ return {
15503
+ start: customRange?.from ?? new Date(now.getTime() - PRESET_MS$2["24h"]),
15504
+ end: customRange?.to ?? now
15505
+ };
15506
+ }
15507
+ function useMetricsFilters() {
15508
+ const { datePreset, customRange } = useMetrics();
15509
+ const timestamp = buildTimestamp(datePreset, customRange);
15510
+ return { datePreset, customRange, timestamp };
15511
+ }
15512
+
15513
+ function useAgentRunsKpiMetrics() {
15514
+ const client = react.useMastraClient();
15515
+ const { datePreset, customRange, timestamp } = useMetricsFilters();
15516
+ return reactQuery.useQuery({
15517
+ queryKey: ["metrics", "agent-runs-kpi", datePreset, customRange],
15518
+ queryFn: () => client.getMetricAggregate({
15519
+ name: ["mastra_agent_duration_ms"],
15520
+ aggregation: "count",
15521
+ filters: { timestamp },
15522
+ comparePeriod: "previous_period"
15523
+ })
15524
+ });
15525
+ }
15526
+
15527
+ function useAvgScoreKpiMetrics() {
15528
+ const client = react.useMastraClient();
15529
+ const { datePreset, customRange, timestamp } = useMetricsFilters();
15530
+ return reactQuery.useQuery({
15531
+ queryKey: ["metrics", "avg-score-kpi", datePreset, customRange],
15532
+ queryFn: async () => {
15533
+ const scorersMap = await client.listScorers();
15534
+ const scorerIds = Object.keys(scorersMap ?? {});
15535
+ if (scorerIds.length === 0) {
15536
+ return { value: null, previousValue: null, changePercent: null };
15537
+ }
15538
+ const filters = {
15539
+ timestamp: { start: timestamp.start, end: timestamp.end }
15540
+ };
15541
+ const results = await Promise.all(
15542
+ scorerIds.map(async (scorerId) => {
15543
+ const [avg2, count] = await Promise.all([
15544
+ client.getScoreAggregate({ scorerId, aggregation: "avg", filters }),
15545
+ client.getScoreAggregate({ scorerId, aggregation: "count", filters })
15546
+ ]);
15547
+ return { avg: avg2.value ?? 0, count: count.value ?? 0 };
15548
+ })
15549
+ );
15550
+ const withData = results.filter((r) => r.count > 0);
15551
+ if (withData.length === 0) {
15552
+ return { value: null, previousValue: null, changePercent: null };
15553
+ }
15554
+ const totalCount = withData.reduce((sum, r) => sum + r.count, 0);
15555
+ const weightedSum = withData.reduce((sum, r) => sum + r.avg * r.count, 0);
15556
+ const avg = weightedSum / totalCount;
15557
+ return { value: Math.round(avg * 100) / 100, previousValue: null, changePercent: null };
15558
+ }
15559
+ });
15560
+ }
15561
+
15562
+ function useModelCostKpiMetrics() {
15563
+ const client = react.useMastraClient();
15564
+ const { datePreset, customRange, timestamp } = useMetricsFilters();
15565
+ return reactQuery.useQuery({
15566
+ queryKey: ["metrics", "model-cost-kpi", datePreset, customRange],
15567
+ queryFn: async () => {
15568
+ const res = await client.getMetricAggregate({
15569
+ name: ["mastra_model_total_input_tokens", "mastra_model_total_output_tokens"],
15570
+ aggregation: "sum",
15571
+ filters: { timestamp },
15572
+ comparePeriod: "previous_period"
15573
+ });
15574
+ return {
15575
+ cost: res.estimatedCost ?? null,
15576
+ costUnit: res.costUnit ?? null,
15577
+ previousCost: res.previousEstimatedCost ?? null,
15578
+ costChangePercent: res.costChangePercent ?? null
15579
+ };
15580
+ }
15581
+ });
15582
+ }
15583
+
15584
+ function useTotalTokensKpiMetrics() {
15585
+ const client = react.useMastraClient();
15586
+ const { datePreset, customRange, timestamp } = useMetricsFilters();
15587
+ return reactQuery.useQuery({
15588
+ queryKey: ["metrics", "total-tokens-kpi", datePreset, customRange],
15589
+ queryFn: async () => {
15590
+ const [input, output] = await Promise.all([
15591
+ client.getMetricAggregate({
15592
+ name: ["mastra_model_total_input_tokens"],
15593
+ aggregation: "sum",
15594
+ filters: { timestamp },
15595
+ comparePeriod: "previous_period"
15596
+ }),
15597
+ client.getMetricAggregate({
15598
+ name: ["mastra_model_total_output_tokens"],
15599
+ aggregation: "sum",
15600
+ filters: { timestamp },
15601
+ comparePeriod: "previous_period"
15602
+ })
15603
+ ]);
15604
+ const hasCurrent = input.value != null || output.value != null;
15605
+ const hasPrevious = input.previousValue != null || output.previousValue != null;
15606
+ const value = (input.value ?? 0) + (output.value ?? 0);
15607
+ const previousValue = (input.previousValue ?? 0) + (output.previousValue ?? 0);
15608
+ const changePercent = hasPrevious && previousValue > 0 ? (value - previousValue) / previousValue * 100 : null;
15609
+ return {
15610
+ value: hasCurrent ? value : null,
15611
+ previousValue: hasPrevious ? previousValue : null,
15612
+ changePercent
15613
+ };
15614
+ }
15615
+ });
15616
+ }
15617
+
15618
+ function useModelUsageCostMetrics() {
15619
+ const client = react.useMastraClient();
15620
+ const { datePreset, customRange, timestamp } = useMetricsFilters();
15621
+ return reactQuery.useQuery({
15622
+ queryKey: ["metrics", "model-usage-cost", datePreset, customRange],
15623
+ queryFn: async () => {
15624
+ const metrics = [
15625
+ "mastra_model_total_input_tokens",
15626
+ "mastra_model_total_output_tokens",
15627
+ "mastra_model_input_cache_read_tokens",
15628
+ "mastra_model_input_cache_write_tokens"
15629
+ ];
15630
+ const [inputRes, outputRes, cacheReadRes, cacheWriteRes] = await Promise.all(
15631
+ metrics.map(
15632
+ (name) => client.getMetricBreakdown({
15633
+ name: [name],
15634
+ groupBy: ["model"],
15635
+ aggregation: "sum",
15636
+ filters: { timestamp }
15637
+ })
15638
+ )
15639
+ );
15640
+ const modelMap = /* @__PURE__ */ new Map();
15641
+ const ensureModel = (model) => {
15642
+ if (!modelMap.has(model)) {
15643
+ modelMap.set(model, { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: null, costUnit: null });
15644
+ }
15645
+ return modelMap.get(model);
15646
+ };
15647
+ const addCost = (entry, group) => {
15648
+ if (group.estimatedCost != null) {
15649
+ entry.cost = (entry.cost ?? 0) + group.estimatedCost;
15650
+ if (group.costUnit) entry.costUnit = group.costUnit;
15651
+ }
15652
+ };
15653
+ for (const group of inputRes.groups) {
15654
+ const m = group.dimensions.model ?? "unknown";
15655
+ const entry = ensureModel(m);
15656
+ entry.input = group.value;
15657
+ addCost(entry, group);
15658
+ }
15659
+ for (const group of outputRes.groups) {
15660
+ const m = group.dimensions.model ?? "unknown";
15661
+ const entry = ensureModel(m);
15662
+ entry.output = group.value;
15663
+ addCost(entry, group);
15664
+ }
15665
+ for (const group of cacheReadRes.groups) {
15666
+ const m = group.dimensions.model ?? "unknown";
15667
+ const entry = ensureModel(m);
15668
+ entry.cacheRead = group.value;
15669
+ addCost(entry, group);
15670
+ }
15671
+ for (const group of cacheWriteRes.groups) {
15672
+ const m = group.dimensions.model ?? "unknown";
15673
+ const entry = ensureModel(m);
15674
+ entry.cacheWrite = group.value;
15675
+ addCost(entry, group);
15676
+ }
15677
+ return Array.from(modelMap.entries()).map(([model, vals]) => ({
15678
+ model,
15679
+ input: formatCompact(vals.input),
15680
+ output: formatCompact(vals.output),
15681
+ cacheRead: formatCompact(vals.cacheRead),
15682
+ cacheWrite: formatCompact(vals.cacheWrite),
15683
+ cost: vals.cost,
15684
+ costUnit: vals.costUnit
15685
+ })).sort((a, b) => a.model.localeCompare(b.model));
15686
+ }
15687
+ });
15688
+ }
15689
+
15690
+ async function fetchPercentiles(client, metricName, timestamp) {
15691
+ const res = await client.getMetricPercentiles({
15692
+ name: metricName,
15693
+ percentiles: [0.5, 0.95],
15694
+ interval: "1h",
15695
+ filters: { timestamp }
15696
+ });
15697
+ const p50Series = res.series.find((s) => s.percentile === 0.5);
15698
+ const p95Series = res.series.find((s) => s.percentile === 0.95);
15699
+ if (!p50Series || !p95Series) return [];
15700
+ const p95Map = new Map(p95Series.points.map((p) => [new Date(p.timestamp).getTime(), p.value]));
15701
+ return p50Series.points.map((p) => {
15702
+ const ts = new Date(p.timestamp);
15703
+ return {
15704
+ time: ts.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false }),
15705
+ p50: Math.round(p.value),
15706
+ p95: Math.round(p95Map.get(ts.getTime()) ?? 0)
15707
+ };
15708
+ });
15709
+ }
15710
+ function useLatencyMetrics() {
15711
+ const client = react.useMastraClient();
15712
+ const { datePreset, customRange, timestamp } = useMetricsFilters();
15713
+ return reactQuery.useQuery({
15714
+ queryKey: ["metrics", "latency", datePreset, customRange],
15715
+ queryFn: async () => {
15716
+ const [agentData, workflowData, toolData] = await Promise.all([
15717
+ fetchPercentiles(client, "mastra_agent_duration_ms", timestamp),
15718
+ fetchPercentiles(client, "mastra_workflow_duration_ms", timestamp),
15719
+ fetchPercentiles(client, "mastra_tool_duration_ms", timestamp)
15720
+ ]);
15721
+ return { agentData, workflowData, toolData };
15722
+ }
15723
+ });
15724
+ }
15725
+
15726
+ async function fetchVolume(client, metricName, timestamp) {
15727
+ const res = await client.getMetricBreakdown({
15728
+ name: [metricName],
15729
+ groupBy: ["entityName", "status"],
15730
+ aggregation: "count",
15731
+ filters: { timestamp }
15732
+ });
15733
+ const map = /* @__PURE__ */ new Map();
15734
+ for (const group of res.groups) {
15735
+ const name = group.dimensions.entityName ?? "unknown";
15736
+ const status = group.dimensions.status ?? "ok";
15737
+ if (!map.has(name)) {
15738
+ map.set(name, { completed: 0, errors: 0 });
15739
+ }
15740
+ const entry = map.get(name);
15741
+ if (status === "error") {
15742
+ entry.errors += group.value;
15743
+ } else {
15744
+ entry.completed += group.value;
15745
+ }
15746
+ }
15747
+ return Array.from(map.entries()).map(([name, vals]) => ({ name, ...vals })).sort((a, b) => b.completed + b.errors - (a.completed + a.errors));
15748
+ }
15749
+ function useTraceVolumeMetrics() {
15750
+ const client = react.useMastraClient();
15751
+ const { datePreset, customRange, timestamp } = useMetricsFilters();
15752
+ return reactQuery.useQuery({
15753
+ queryKey: ["metrics", "trace-volume", datePreset, customRange],
15754
+ queryFn: async () => {
15755
+ const [agentData, workflowData, toolData] = await Promise.all([
15756
+ fetchVolume(client, "mastra_agent_duration_ms", timestamp),
15757
+ fetchVolume(client, "mastra_workflow_duration_ms", timestamp),
15758
+ fetchVolume(client, "mastra_tool_duration_ms", timestamp)
15759
+ ]);
15760
+ return { agentData, workflowData, toolData };
15761
+ }
15762
+ });
15763
+ }
15764
+
15765
+ function useScoresMetrics() {
15766
+ const client = react.useMastraClient();
15767
+ const { datePreset, customRange, timestamp } = useMetricsFilters();
15768
+ return reactQuery.useQuery({
15769
+ queryKey: ["metrics", "scores-card", datePreset, customRange],
15770
+ queryFn: async () => {
15771
+ const filters = {
15772
+ timestamp: { start: timestamp.start, end: timestamp.end }
15773
+ };
15774
+ const scorersMap = await client.listScorers();
15775
+ const scorerIds = Object.keys(scorersMap ?? {});
15776
+ if (scorerIds.length === 0) {
15777
+ return { summaryData: [], overTimeData: [], scorerNames: [], avgScore: null };
15778
+ }
15779
+ const summaryResults = await Promise.all(
15780
+ scorerIds.map(async (scorerId) => {
15781
+ const [avg, min, max, count] = await Promise.all([
15782
+ client.getScoreAggregate({ scorerId, aggregation: "avg", filters }),
15783
+ client.getScoreAggregate({ scorerId, aggregation: "min", filters }),
15784
+ client.getScoreAggregate({ scorerId, aggregation: "max", filters }),
15785
+ client.getScoreAggregate({ scorerId, aggregation: "count", filters })
15786
+ ]);
15787
+ return {
15788
+ scorer: scorerId,
15789
+ avg: avg.value ?? 0,
15790
+ min: min.value ?? 0,
15791
+ max: max.value ?? 0,
15792
+ count: count.value ?? 0
15793
+ };
15794
+ })
15795
+ );
15796
+ const summaryData = summaryResults.filter((s) => s.count > 0);
15797
+ const scorerNames = summaryData.map((s) => s.scorer);
15798
+ if (summaryData.length === 0) {
15799
+ return { summaryData: [], overTimeData: [], scorerNames: [], avgScore: null };
15800
+ }
15801
+ const totalWeighted = summaryData.reduce((s, d) => s + d.avg * d.count, 0);
15802
+ const totalCount = summaryData.reduce((s, d) => s + d.count, 0);
15803
+ const avgScore = totalCount ? Math.round(totalWeighted / totalCount * 100) / 100 : 0;
15804
+ const interval = "1h";
15805
+ const timeSeriesResults = await Promise.all(
15806
+ scorerNames.map(
15807
+ (scorerId) => client.getScoreTimeSeries({
15808
+ scorerId,
15809
+ interval,
15810
+ aggregation: "avg",
15811
+ filters
15812
+ })
15813
+ )
15814
+ );
15815
+ const hourBuckets = /* @__PURE__ */ new Map();
15816
+ for (let i = 0; i < scorerNames.length; i++) {
15817
+ const scorerId = scorerNames[i];
15818
+ const series = timeSeriesResults[i]?.series ?? [];
15819
+ for (const s of series) {
15820
+ for (const point of s.points) {
15821
+ const ts = new Date(point.timestamp);
15822
+ const hourKey = ts.toLocaleTimeString("en-US", {
15823
+ hour: "2-digit",
15824
+ minute: "2-digit",
15825
+ hour12: false
15826
+ });
15827
+ if (!hourBuckets.has(hourKey)) {
15828
+ hourBuckets.set(hourKey, /* @__PURE__ */ new Map());
15829
+ }
15830
+ const scorerMap = hourBuckets.get(hourKey);
15831
+ if (!scorerMap.has(scorerId)) {
15832
+ scorerMap.set(scorerId, { sum: 0, count: 0 });
15833
+ }
15834
+ const acc = scorerMap.get(scorerId);
15835
+ acc.sum += point.value;
15836
+ acc.count += 1;
15837
+ }
15838
+ }
15839
+ }
15840
+ const overTimeData = Array.from(hourBuckets.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([hourKey, scorerMap]) => {
15841
+ const point = { time: hourKey };
15842
+ for (const [scorerId, acc] of scorerMap) {
15843
+ point[scorerId] = +(acc.sum / acc.count).toFixed(2);
15844
+ }
15845
+ return point;
15846
+ });
15847
+ return {
15848
+ summaryData,
15849
+ overTimeData,
15850
+ scorerNames,
15851
+ avgScore
15852
+ };
15853
+ }
15854
+ });
15855
+ }
15856
+
15857
+ function useTokenUsageByAgentMetrics() {
15858
+ const client = react.useMastraClient();
15859
+ const { datePreset, customRange, timestamp } = useMetricsFilters();
15860
+ return reactQuery.useQuery({
15861
+ queryKey: ["metrics", "token-usage-by-agent", datePreset, customRange],
15862
+ queryFn: async () => {
15863
+ const [inputRes, outputRes, cacheReadRes, cacheWriteRes] = await Promise.all([
15864
+ client.getMetricBreakdown({
15865
+ name: ["mastra_model_total_input_tokens"],
15866
+ groupBy: ["entityName"],
15867
+ aggregation: "sum",
15868
+ filters: { timestamp }
15869
+ }),
15870
+ client.getMetricBreakdown({
15871
+ name: ["mastra_model_total_output_tokens"],
15872
+ groupBy: ["entityName"],
15873
+ aggregation: "sum",
15874
+ filters: { timestamp }
15875
+ }),
15876
+ client.getMetricBreakdown({
15877
+ name: ["mastra_model_input_cache_read_tokens"],
15878
+ groupBy: ["entityName"],
15879
+ aggregation: "sum",
15880
+ filters: { timestamp }
15881
+ }),
15882
+ client.getMetricBreakdown({
15883
+ name: ["mastra_model_input_cache_write_tokens"],
15884
+ groupBy: ["entityName"],
15885
+ aggregation: "sum",
15886
+ filters: { timestamp }
15887
+ })
15888
+ ]);
15889
+ const agentMap = /* @__PURE__ */ new Map();
15890
+ const ensure = (name) => {
15891
+ if (!agentMap.has(name)) {
15892
+ agentMap.set(name, { input: 0, output: 0, cost: null, costUnit: null });
15893
+ }
15894
+ return agentMap.get(name);
15895
+ };
15896
+ const addCost = (entry, group) => {
15897
+ if (group.estimatedCost != null) {
15898
+ entry.cost = (entry.cost ?? 0) + group.estimatedCost;
15899
+ if (group.costUnit) entry.costUnit = group.costUnit;
15900
+ }
15901
+ };
15902
+ for (const group of inputRes.groups) {
15903
+ const name = group.dimensions.entityName ?? "unknown";
15904
+ const entry = ensure(name);
15905
+ entry.input = group.value;
15906
+ addCost(entry, group);
15907
+ }
15908
+ for (const group of outputRes.groups) {
15909
+ const name = group.dimensions.entityName ?? "unknown";
15910
+ const entry = ensure(name);
15911
+ entry.output = group.value;
15912
+ addCost(entry, group);
15913
+ }
15914
+ for (const group of cacheReadRes.groups) {
15915
+ const name = group.dimensions.entityName ?? "unknown";
15916
+ const entry = ensure(name);
15917
+ addCost(entry, group);
15918
+ }
15919
+ for (const group of cacheWriteRes.groups) {
15920
+ const name = group.dimensions.entityName ?? "unknown";
15921
+ const entry = ensure(name);
15922
+ addCost(entry, group);
15923
+ }
15924
+ return Array.from(agentMap.entries()).map(([name, vals]) => ({
15925
+ name,
15926
+ input: vals.input,
15927
+ output: vals.output,
15928
+ total: vals.input + vals.output,
15929
+ cost: vals.cost,
15930
+ costUnit: vals.costUnit
15931
+ })).sort((a, b) => b.total - a.total);
15932
+ }
15933
+ });
15934
+ }
15935
+
15936
+ const formatHierarchicalSpans = (spans) => {
15937
+ if (!spans || spans.length === 0) {
15938
+ return [];
15939
+ }
15940
+ const overallEndDate = spans.reduce(
15941
+ (latest, span) => {
15942
+ const endDate = span?.endedAt ? new Date(span.endedAt) : void 0;
15943
+ return endDate && (!latest || endDate > latest) ? endDate : latest;
15944
+ },
15945
+ null
15946
+ );
15947
+ const spanMap = /* @__PURE__ */ new Map();
15948
+ const rootSpans = [];
15949
+ spans.forEach((spanRecord) => {
15950
+ const startDate = new Date(spanRecord.startedAt);
15951
+ const endDate = spanRecord.endedAt ? new Date(spanRecord.endedAt) : void 0;
15952
+ const uiSpan = {
15953
+ id: spanRecord.spanId,
15954
+ name: spanRecord.name,
15955
+ type: spanRecord.spanType,
15956
+ latency: endDate ? endDate.getTime() - startDate.getTime() : 0,
15957
+ startTime: startDate.toISOString(),
15958
+ endTime: endDate ? endDate.toISOString() : void 0,
15959
+ spans: [],
15960
+ parentSpanId: spanRecord.parentSpanId
15961
+ };
15962
+ spanMap.set(spanRecord.spanId, uiSpan);
15963
+ });
15964
+ spans.forEach((spanRecord) => {
15965
+ const uiSpan = spanMap.get(spanRecord.spanId);
15966
+ if (spanRecord?.parentSpanId == null) {
15967
+ if (overallEndDate && uiSpan.endTime && overallEndDate > new Date(uiSpan.endTime)) {
15968
+ uiSpan.endTime = overallEndDate.toISOString();
15969
+ const overallEndTime = new Date(overallEndDate).getTime();
15970
+ const spanStartTime = new Date(uiSpan.startTime).getTime();
15971
+ uiSpan.latency = overallEndTime - spanStartTime;
15972
+ }
15973
+ rootSpans.push(uiSpan);
15974
+ } else {
15975
+ const parent = spanMap.get(spanRecord.parentSpanId);
15976
+ if (parent) {
15977
+ parent.spans.push(uiSpan);
15978
+ } else {
15979
+ rootSpans.push(uiSpan);
15980
+ }
15981
+ }
15982
+ });
15983
+ const sortSpansByStartTime = (spans2) => {
15984
+ return spans2.sort((a, b) => new Date(a.startTime).getTime() - new Date(b.startTime).getTime());
15985
+ };
15986
+ const sortedRootSpans = sortSpansByStartTime(rootSpans);
15987
+ const sortNestedSpans = (spans2) => {
15988
+ spans2.forEach((span) => {
15989
+ if (span.spans && span.spans.length > 0) {
15990
+ span.spans = sortSpansByStartTime(span.spans);
15991
+ sortNestedSpans(span.spans);
15992
+ }
15993
+ });
15994
+ };
15995
+ sortNestedSpans(sortedRootSpans);
15996
+ return sortedRootSpans;
15997
+ };
15998
+
15999
+ const spanTypePrefixes = ["agent", "workflow", "model", "mcp", "tool", "memory", "workspace", "other"];
16000
+ const spanTypeToUiElements = {
16001
+ agent: {
16002
+ icon: /* @__PURE__ */ jsxRuntime.jsx(AgentIcon, {}),
16003
+ color: "oklch(0.75 0.15 250)",
16004
+ label: "Agent",
16005
+ bgColor: "oklch(0.75 0.15 250 / 0.1)",
16006
+ typePrefix: "agent"
16007
+ },
16008
+ workflow: {
16009
+ icon: /* @__PURE__ */ jsxRuntime.jsx(WorkflowIcon, {}),
16010
+ color: "oklch(0.75 0.15 200)",
16011
+ label: "Workflow",
16012
+ bgColor: "oklch(0.75 0.15 200 / 0.1)",
16013
+ typePrefix: "workflow"
16014
+ },
16015
+ model: {
16016
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BrainIcon, {}),
16017
+ color: "oklch(0.75 0.15 320)",
16018
+ label: "Model",
16019
+ bgColor: "oklch(0.75 0.15 320 / 0.1)",
16020
+ typePrefix: "model"
16021
+ },
16022
+ mcp: {
16023
+ icon: /* @__PURE__ */ jsxRuntime.jsx(McpServerIcon, {}),
16024
+ color: "oklch(0.75 0.15 160)",
16025
+ label: "MCP",
16026
+ bgColor: "oklch(0.75 0.15 160 / 0.1)",
16027
+ typePrefix: "mcp"
16028
+ },
16029
+ tool: {
16030
+ icon: /* @__PURE__ */ jsxRuntime.jsx(ToolsIcon, {}),
16031
+ color: "oklch(0.75 0.15 100)",
16032
+ label: "Tool",
16033
+ bgColor: "oklch(0.75 0.15 100 / 0.1)",
16034
+ typePrefix: "tool"
16035
+ },
16036
+ memory: {
16037
+ icon: /* @__PURE__ */ jsxRuntime.jsx(MemoryIcon, {}),
16038
+ color: "oklch(0.75 0.15 60)",
16039
+ label: "Memory",
16040
+ bgColor: "oklch(0.75 0.15 60 / 0.1)",
16041
+ typePrefix: "memory"
16042
+ },
16043
+ workspace: {
16044
+ icon: /* @__PURE__ */ jsxRuntime.jsx(FolderIcon, {}),
16045
+ color: "oklch(0.75 0.15 40)",
16046
+ label: "Workspace",
16047
+ bgColor: "oklch(0.75 0.15 40 / 0.1)",
16048
+ typePrefix: "workspace"
16049
+ }
16050
+ };
16051
+ const otherSpanType = {
16052
+ color: "oklch(0.65 0 0)",
16053
+ label: "Other",
16054
+ typePrefix: "other"
16055
+ };
16056
+ function getSpanTypeUi(type) {
16057
+ const typePrefix = type?.toLowerCase().split("_")[0];
16058
+ return spanTypeToUiElements[typePrefix] ?? otherSpanType;
16059
+ }
16060
+
16061
+ function isTokenDetailsObject(value) {
16062
+ return typeof value === "object" && value !== null;
16063
+ }
16064
+ const detailKeyLabels = {
16065
+ text: "Text",
16066
+ cacheRead: "Cache Read",
16067
+ cacheWrite: "Cache Write",
16068
+ audio: "Audio",
16069
+ image: "Image",
16070
+ reasoning: "Reasoning"
16071
+ };
16072
+ function SpanTokenUsage({ usage, className }) {
16073
+ if (!usage) return null;
16074
+ const isV5 = "inputTokens" in usage;
16075
+ const legacyTokenPresentations = {
16076
+ promptTokens: { label: "Prompt Tokens", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightIcon, {}) },
16077
+ completionTokens: { label: "Completion Tokens", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightToLineIcon, {}) }
16078
+ };
16079
+ const v5TokenPresentations = {
16080
+ inputTokens: { label: "Input Tokens", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightIcon, {}) },
16081
+ outputTokens: { label: "Output Tokens", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightToLineIcon, {}) },
16082
+ reasoningTokens: { label: "Reasoning Tokens", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightToLineIcon, {}) },
16083
+ cachedInputTokens: { label: "Cached Input Tokens", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightToLineIcon, {}) },
16084
+ inputDetails: { label: "Input Details", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightIcon, {}) },
16085
+ outputDetails: { label: "Output Details", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightToLineIcon, {}) }
16086
+ };
16087
+ const commonTokenPresentations = {
16088
+ totalTokens: { label: "Total LLM Tokens", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CoinsIcon, {}) }
16089
+ };
16090
+ const tokenPresentations = {
16091
+ ...commonTokenPresentations,
16092
+ ...v5TokenPresentations,
16093
+ ...legacyTokenPresentations
16094
+ };
16095
+ const usageKeyOrder = isV5 ? [
16096
+ "totalTokens",
16097
+ "inputTokens",
16098
+ "outputTokens",
16099
+ "reasoningTokens",
16100
+ "cachedInputTokens",
16101
+ "inputDetails",
16102
+ "outputDetails"
16103
+ ] : ["totalTokens", "promptTokens", "completionTokens"];
16104
+ const usageAsArray = Object.entries(usage).filter((entry) => {
16105
+ const value = entry[1];
16106
+ return typeof value === "number" || isTokenDetailsObject(value);
16107
+ }).map(([key, value]) => ({ key, value })).sort((a, b) => usageKeyOrder.indexOf(a.key) - usageKeyOrder.indexOf(b.key));
16108
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex gap-6 flex-wrap", className), children: usageAsArray.map(({ key, value }) => {
16109
+ const isObject = isTokenDetailsObject(value);
16110
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-surface3 p-3 px-4 rounded-lg text-ui-md grow", children: [
16111
+ /* @__PURE__ */ jsxRuntime.jsxs(
16112
+ "div",
16113
+ {
16114
+ className: cn(
16115
+ "grid grid-cols-[1.5rem_1fr_auto] gap-2 items-center",
16116
+ "[&>svg]:w-[1.5em] [&>svg]:h-[1.5em] [&>svg]:opacity-70"
16117
+ ),
16118
+ children: [
16119
+ tokenPresentations?.[key]?.icon,
16120
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-md", children: tokenPresentations?.[key]?.label }),
16121
+ !isObject && /* @__PURE__ */ jsxRuntime.jsx("b", { className: "text-ui-lg", children: value })
16122
+ ]
16123
+ }
16124
+ ),
16125
+ isObject && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-md mt-2 pl-8", children: Object.entries(value).map(([detailKey, detailValue]) => {
16126
+ if (typeof detailValue !== "number") return null;
16127
+ return /* @__PURE__ */ jsxRuntime.jsxs(
16128
+ "dl",
16129
+ {
16130
+ className: "grid grid-cols-[1fr_auto] gap-x-4 gap-y-1 justify-between text-neutral3",
16131
+ children: [
16132
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: detailKeyLabels[detailKey] || detailKey }),
16133
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: detailValue })
16134
+ ]
16135
+ },
16136
+ detailKey
16137
+ );
16138
+ }) })
16139
+ ] }, key);
16140
+ }) });
16141
+ }
16142
+
16143
+ function TimelineExpandCol({
16144
+ isSelected,
16145
+ isFaded,
16146
+ isExpanded,
16147
+ toggleChildren,
16148
+ expandAllDescendants,
16149
+ totalDescendants = 0,
16150
+ allDescendantsExpanded,
16151
+ numOfChildren
16152
+ }) {
16153
+ return /* @__PURE__ */ jsxRuntime.jsx(
16154
+ "div",
16155
+ {
16156
+ className: cn("flex items-center justify-end h-full px-1.5", {
16157
+ "opacity-30 [&:hover]:opacity-60": isFaded,
16158
+ "bg-surface4": isSelected
16159
+ }),
16160
+ children: numOfChildren && numOfChildren > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1", children: [
16161
+ /* @__PURE__ */ jsxRuntime.jsxs(ExpandButton, { onClick: () => toggleChildren?.(), children: [
16162
+ allDescendantsExpanded ? totalDescendants : numOfChildren,
16163
+ " ",
16164
+ isExpanded ? allDescendantsExpanded ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUpIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, {})
16165
+ ] }),
16166
+ totalDescendants > numOfChildren && !allDescendantsExpanded && /* @__PURE__ */ jsxRuntime.jsxs(ExpandButton, { onClick: () => expandAllDescendants?.(), children: [
16167
+ totalDescendants,
16168
+ " ",
16169
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsDownIcon, {})
16170
+ ] })
16171
+ ] }) : null
16172
+ }
16173
+ );
16174
+ }
16175
+ function ExpandButton({ onClick, children, className }) {
16176
+ return /* @__PURE__ */ jsxRuntime.jsx("button", { onClick, className: cn("h-full", className), children: /* @__PURE__ */ jsxRuntime.jsx(
16177
+ "div",
16178
+ {
16179
+ className: cn(
16180
+ "flex items-center gap-[0.1rem] text-ui-xs text-neutral5 border border-border1 pl-1.5 pr-0.5 rounded-md transition-all",
16181
+ "hover:text-yellow-500",
16182
+ "[&>svg]:shrink-0 [&>svg]:opacity-80 [&>svg]:w-[0.85rem] [&>svg]:h-[0.85rem] [&>svg]:transition-all"
16183
+ ),
16184
+ children
16185
+ }
16186
+ ) });
16187
+ }
16188
+
16189
+ function TimelineStructureSign({ isLastChild }) {
16190
+ return /* @__PURE__ */ jsxRuntime.jsx(
16191
+ "div",
16192
+ {
16193
+ className: cn(
16194
+ "w-[0.5rem] h-[1.8rem] relative opacity-100 shrink-0",
16195
+ 'after:content-[""] after:absolute after:left-[-1px] after:top-0 after:bottom-0 after:w-[0px] after:border-l-[1px] after:border-neutral3 after:border-dashed ',
16196
+ 'before:content-[""] before:absolute before:left-0 before:top-[50%] before:w-full before:h-[0px] before:border-b-[1px] before:border-neutral3 before:border-dashed',
16197
+ {
16198
+ "after:bottom-[50%]": isLastChild
16199
+ }
16200
+ )
16201
+ }
16202
+ );
16203
+ }
16204
+
16205
+ function TimelineNameCol({
16206
+ span,
16207
+ spanUI: _spanUI,
16208
+ isFaded,
16209
+ depth = 0,
16210
+ onSpanClick,
16211
+ selectedSpanId,
16212
+ isLastChild,
16213
+ hasChildren: _hasChildren,
16214
+ isRootSpan,
16215
+ isExpanded: _isExpanded
16216
+ }) {
16217
+ return /* @__PURE__ */ jsxRuntime.jsxs(
16218
+ "div",
16219
+ {
16220
+ "data-span-id": span.id,
16221
+ "aria-label": `View details for span ${span.name}`,
16222
+ className: cn("rounded-md flex opacity-80 min-h-8 items-center rounded-l-lg", {
16223
+ "opacity-30 [&:hover]:opacity-60": isFaded,
16224
+ "bg-surface4": selectedSpanId === span.id
16225
+ }),
16226
+ style: { paddingLeft: `${depth * 1}rem` },
16227
+ children: [
16228
+ !isRootSpan && /* @__PURE__ */ jsxRuntime.jsx(TimelineStructureSign, { isLastChild }),
16229
+ /* @__PURE__ */ jsxRuntime.jsx(
16230
+ "button",
16231
+ {
16232
+ onClick: () => onSpanClick?.(span.id),
16233
+ className: cn(
16234
+ "text-ui-sm flex items-center text-left gap-1.5 text-neutral6 w-full min-w-0 rounded-md h-full px-2 py-1 transition-colors",
16235
+ "[&>svg]:transition-all [&>svg]:shrink-0 [&>svg]:opacity-0 [&>svg]:w-[1em] [&>svg]:h-[1em] [&>svg]:ml-auto",
16236
+ "hover:bg-surface4 [&:hover>svg]:opacity-60",
16237
+ "focus:outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-accent1"
16238
+ ),
16239
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: span.name })
16240
+ }
16241
+ )
16242
+ ]
16243
+ }
16244
+ );
16245
+ }
16246
+
16247
+ function TimelineTimingCol({
16248
+ span,
16249
+ selectedSpanId,
16250
+ isFaded,
16251
+ overallLatency,
16252
+ overallStartTime,
16253
+ color,
16254
+ chartWidth = "default"
16255
+ }) {
16256
+ const percentageSpanLatency = overallLatency ? Math.ceil(span.latency / overallLatency * 100) : 0;
16257
+ const overallStartTimeDate = overallStartTime ? new Date(overallStartTime) : null;
16258
+ const spanStartTimeDate = span.startTime ? new Date(span.startTime) : null;
16259
+ const spanStartTimeShift = spanStartTimeDate && overallStartTimeDate ? spanStartTimeDate.getTime() - overallStartTimeDate.getTime() : 0;
16260
+ const percentageSpanStartTime = overallLatency && Math.floor(spanStartTimeShift / overallLatency * 100);
16261
+ return /* @__PURE__ */ jsxRuntime.jsxs(HoverCard__namespace.Root, { openDelay: 250, children: [
16262
+ /* @__PURE__ */ jsxRuntime.jsxs(
16263
+ HoverCard__namespace.Trigger,
16264
+ {
16265
+ className: cn(
16266
+ "h-8 p-1 grid grid-cols-[1fr_auto] gap-2 items-center cursor-help pr-2 rounded-r-md",
16267
+ chartWidth === "wide" ? "min-w-72" : "min-w-32",
16268
+ "[&:hover>div]:bg-surface5",
16269
+ {
16270
+ "opacity-30 [&:hover]:opacity-60": isFaded,
16271
+ "bg-surface4": selectedSpanId === span.id
16272
+ }
16273
+ ),
16274
+ children: [
16275
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full p-1.5 rounded-md bg-surface4 transition-colors duration-1000"), children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full h-1.5 rounded-sm overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
16276
+ "div",
16277
+ {
16278
+ className: cn("bg-neutral1 absolute rounded-sm h-1.5 top-0"),
16279
+ style: {
16280
+ width: percentageSpanLatency ? `${percentageSpanLatency}%` : "2px",
16281
+ left: `${percentageSpanStartTime || 0}%`,
16282
+ backgroundColor: color
16283
+ }
16284
+ }
16285
+ ) }) }),
16286
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex justify-end text-neutral3 text-ui-xs"), children: [
16287
+ (span.latency / 1e3).toFixed(3),
16288
+ " s"
16289
+ ] })
16290
+ ]
16291
+ }
16292
+ ),
16293
+ /* @__PURE__ */ jsxRuntime.jsx(HoverCard__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
16294
+ HoverCard__namespace.Content,
16295
+ {
16296
+ className: "z-50 w-auto max-w-100 rounded-md bg-surface4 p-2 px-4 pr-6 text-ui-sm text-neutral5 border border-border1",
16297
+ sideOffset: 5,
16298
+ side: "top",
16299
+ children: [
16300
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("text-ui-sm flex items-center gap-2 mb-2 mt-1"), children: "Span Timing" }),
16301
+ /* @__PURE__ */ jsxRuntime.jsxs(DataKeysAndValues, { children: [
16302
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Latency" }),
16303
+ /* @__PURE__ */ jsxRuntime.jsxs(DataKeysAndValues.Value, { children: [
16304
+ span.latency,
16305
+ " ms"
16306
+ ] }),
16307
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Started at" }),
16308
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: span.startTime ? format.format(new Date(span.startTime), "hh:mm:ss:SSS a") : "-" }),
16309
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Ended at" }),
16310
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: span.endTime ? format.format(new Date(span.endTime), "hh:mm:ss:SSS a") : "-" }),
16311
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Start Shift" }),
16312
+ /* @__PURE__ */ jsxRuntime.jsxs(DataKeysAndValues.Value, { children: [
16313
+ spanStartTimeShift,
16314
+ "ms"
16315
+ ] })
16316
+ ] }),
16317
+ /* @__PURE__ */ jsxRuntime.jsx(HoverCard__namespace.Arrow, { className: "fill-surface5" })
16318
+ ]
16319
+ }
16320
+ ) })
16321
+ ] });
16322
+ }
16323
+
16324
+ function computeTraceStatus(span) {
16325
+ if (span.error != null) return "error" /* ERROR */;
16326
+ if (span.endedAt == null) return "running" /* RUNNING */;
16327
+ return "success" /* SUCCESS */;
16328
+ }
16329
+ function TraceKeysAndValues({ rootSpan, numOfCol = 2, className }) {
16330
+ const startedAt = rootSpan.startedAt ? new Date(rootSpan.startedAt) : null;
16331
+ const endedAt = rootSpan.endedAt ? new Date(rootSpan.endedAt) : null;
16332
+ const status = computeTraceStatus(rootSpan);
16333
+ const statusLabel = status === "error" /* ERROR */ ? "ERROR" : status === "running" /* RUNNING */ ? "RUNNING" : "SUCCESS";
16334
+ return /* @__PURE__ */ jsxRuntime.jsxs(DataKeysAndValues, { numOfCol, className, children: [
16335
+ rootSpan.entityId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16336
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Entity Id" }),
16337
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: rootSpan.entityName || rootSpan.entityId })
16338
+ ] }),
16339
+ rootSpan.entityType && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16340
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Entity Type" }),
16341
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: rootSpan.entityType })
16342
+ ] }),
16343
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Status" }),
16344
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: statusLabel }),
16345
+ startedAt && endedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16346
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Duration" }),
16347
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: `${(endedAt.getTime() - startedAt.getTime()).toLocaleString()}ms` })
16348
+ ] }),
16349
+ startedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16350
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Started at" }),
16351
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: dateFns.format(startedAt, "MMM dd, h:mm:ss.SSS aaa") })
16352
+ ] }),
16353
+ endedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16354
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Ended at" }),
16355
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: dateFns.format(endedAt, "MMM dd, h:mm:ss.SSS aaa") })
16356
+ ] })
16357
+ ] });
16358
+ }
16359
+
16360
+ function getSpanDescendantIds(span) {
16361
+ if (!span.spans || span.spans.length === 0) {
16362
+ return [];
16363
+ }
16364
+ const descendantIds = [];
16365
+ span.spans.forEach((childSpan) => {
16366
+ descendantIds.push(childSpan.id);
16367
+ descendantIds.push(...getSpanDescendantIds(childSpan));
16368
+ });
16369
+ return descendantIds;
16370
+ }
16371
+ function getAllSpanIds(spans) {
16372
+ const ids = [];
16373
+ for (const span of spans) {
16374
+ ids.push(span.id);
16375
+ ids.push(...getSpanDescendantIds(span));
16376
+ }
16377
+ return ids;
16378
+ }
16379
+
16380
+ function TraceTimelineSpan({
16381
+ span,
16382
+ depth = 0,
16383
+ onSpanClick,
16384
+ selectedSpanId,
16385
+ isLastChild,
16386
+ overallLatency,
16387
+ overallStartTime,
16388
+ fadedTypes,
16389
+ searchPhrase,
16390
+ featuredSpanIds,
16391
+ expandedSpanIds,
16392
+ setExpandedSpanIds,
16393
+ chartWidth
16394
+ }) {
16395
+ const hasChildren = span.spans && span.spans.length > 0;
16396
+ const numOfChildren = span.spans ? span.spans.length : 0;
16397
+ const allDescendantIds = getSpanDescendantIds(span);
16398
+ const totalDescendants = allDescendantIds.length;
16399
+ const isRootSpan = depth === 0;
16400
+ const spanUI = getSpanTypeUi(span?.type);
16401
+ const isExpanded = expandedSpanIds ? expandedSpanIds.includes(span.id) : false;
16402
+ const isFadedBySearch = featuredSpanIds && featuredSpanIds.length > 0 ? !featuredSpanIds.includes(span.id) : false;
16403
+ const isFadedByType = fadedTypes && fadedTypes.length > 0 ? fadedTypes.includes(spanUI?.typePrefix || "") : false;
16404
+ const isFaded = isFadedByType || isFadedBySearch;
16405
+ React.useEffect(() => {
16406
+ if (!featuredSpanIds || allDescendantIds.length === 0) return;
16407
+ if (isExpanded) return;
16408
+ const hasFeaturedDescendant = allDescendantIds.some((id) => featuredSpanIds.includes(id));
16409
+ if (hasFeaturedDescendant && setExpandedSpanIds) {
16410
+ setExpandedSpanIds((prev) => !prev || prev.includes(span.id) ? prev ?? [span.id] : [...prev, span.id]);
16411
+ }
16412
+ }, [featuredSpanIds, allDescendantIds]);
16413
+ const toggleChildren = () => {
16414
+ if (!setExpandedSpanIds) return;
16415
+ setExpandedSpanIds((prev) => {
16416
+ if (!prev) return prev;
16417
+ const idsToRemove = /* @__PURE__ */ new Set([span.id, ...allDescendantIds]);
16418
+ return isExpanded ? prev.filter((id) => !idsToRemove.has(id)) : [...prev, span.id];
16419
+ });
16420
+ };
16421
+ const expandAllDescendants = () => {
16422
+ if (!setExpandedSpanIds) return;
16423
+ setExpandedSpanIds((prev) => {
16424
+ if (!prev) return prev;
16425
+ return Array.from(/* @__PURE__ */ new Set([...prev, span.id, ...allDescendantIds]));
16426
+ });
16427
+ };
16428
+ const allDescendantsExpanded = allDescendantIds.every((id) => expandedSpanIds?.includes(id));
16429
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16430
+ /* @__PURE__ */ jsxRuntime.jsx(
16431
+ TimelineNameCol,
16432
+ {
16433
+ span,
16434
+ spanUI,
16435
+ isFaded,
16436
+ depth,
16437
+ onSpanClick,
16438
+ selectedSpanId,
16439
+ isLastChild,
16440
+ hasChildren,
16441
+ isRootSpan,
16442
+ isExpanded
16443
+ }
16444
+ ),
16445
+ /* @__PURE__ */ jsxRuntime.jsx(
16446
+ TimelineExpandCol,
16447
+ {
16448
+ isSelected: selectedSpanId === span.id,
16449
+ isFaded,
16450
+ isExpanded,
16451
+ toggleChildren,
16452
+ expandAllDescendants,
16453
+ totalDescendants,
16454
+ allDescendantsExpanded,
16455
+ numOfChildren
16456
+ }
16457
+ ),
16458
+ /* @__PURE__ */ jsxRuntime.jsx(
16459
+ TimelineTimingCol,
16460
+ {
16461
+ span,
16462
+ selectedSpanId,
16463
+ isFaded,
16464
+ overallLatency,
16465
+ overallStartTime,
16466
+ color: spanUI?.color,
16467
+ chartWidth
16468
+ }
16469
+ ),
16470
+ hasChildren && isExpanded && span.spans?.map((childSpan, idx, array) => {
16471
+ const isLast = idx === array.length - 1;
16472
+ return /* @__PURE__ */ jsxRuntime.jsx(
16473
+ TraceTimelineSpan,
16474
+ {
16475
+ span: childSpan,
16476
+ depth: depth + 1,
16477
+ onSpanClick,
16478
+ selectedSpanId,
16479
+ isLastChild: isLast,
16480
+ overallLatency,
16481
+ overallStartTime,
16482
+ fadedTypes,
16483
+ searchPhrase,
16484
+ expandedSpanIds,
16485
+ setExpandedSpanIds,
16486
+ featuredSpanIds,
16487
+ chartWidth
16488
+ },
16489
+ childSpan.id
16490
+ );
16491
+ })
16492
+ ] });
16493
+ }
16494
+
16495
+ function TraceTimeline({
16496
+ hierarchicalSpans = [],
16497
+ onSpanClick,
16498
+ selectedSpanId,
16499
+ isLoading,
16500
+ fadedTypes,
16501
+ expandedSpanIds,
16502
+ setExpandedSpanIds,
16503
+ featuredSpanIds,
16504
+ chartWidth = "default"
16505
+ }) {
16506
+ const overallLatency = hierarchicalSpans?.[0]?.latency || 0;
16507
+ const overallStartTime = hierarchicalSpans?.[0]?.startTime || "";
16508
+ const usedSpanTypes = React.useMemo(() => {
16509
+ const collectTypes = (spans) => {
16510
+ const types2 = /* @__PURE__ */ new Set();
16511
+ for (const span of spans) {
16512
+ const prefix = span.type?.toLowerCase().split("_")[0];
16513
+ if (prefix) types2.add(prefix);
16514
+ if (span.spans) {
16515
+ for (const t of collectTypes(span.spans)) types2.add(t);
16516
+ }
16517
+ }
16518
+ return types2;
16519
+ };
16520
+ const types = collectTypes(hierarchicalSpans);
16521
+ const hasOther = [...types].some((t) => !spanTypePrefixes.includes(t));
16522
+ const known = spanTypePrefixes.filter((p) => p !== "other" && types.has(p));
16523
+ if (hasOther) known.push("other");
16524
+ return known;
16525
+ }, [hierarchicalSpans]);
16526
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(
16527
+ "div",
16528
+ {
16529
+ className: cn(
16530
+ "flex items-center text-ui-sm gap-3 bg-surface3/50 rounded-md p-3 justify-center text-neutral3",
16531
+ "[&_svg]:w-[1.25em] [&_svg]:h-[1.25em] [&_svg]:opacity-50"
16532
+ ),
16533
+ children: [
16534
+ /* @__PURE__ */ jsxRuntime.jsx(Spinner, {}),
16535
+ " Loading Trace Timeline ..."
16536
+ ]
16537
+ }
16538
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16539
+ usedSpanTypes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-3 px-2 py-1.5 justify-end", children: usedSpanTypes.map((type) => {
16540
+ const spanUI = getSpanTypeUi(type);
16541
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-ui-sm text-neutral3", children: [
16542
+ /* @__PURE__ */ jsxRuntime.jsx(
16543
+ "span",
16544
+ {
16545
+ className: "inline-block w-1.5 h-1.5 rounded-full shrink-0",
16546
+ style: { backgroundColor: spanUI?.color }
16547
+ }
16548
+ ),
16549
+ spanUI?.label || type
16550
+ ] }, type);
16551
+ }) }),
16552
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-[minmax(0,1fr)_auto_auto] items-start content-start gap-y-px overflow-hidden py-1", children: hierarchicalSpans?.map((span) => /* @__PURE__ */ jsxRuntime.jsx(
16553
+ TraceTimelineSpan,
16554
+ {
16555
+ span,
16556
+ onSpanClick,
16557
+ selectedSpanId,
16558
+ overallLatency,
16559
+ overallStartTime,
16560
+ fadedTypes,
16561
+ featuredSpanIds,
16562
+ expandedSpanIds,
16563
+ setExpandedSpanIds,
16564
+ chartWidth
16565
+ },
16566
+ span.id
16567
+ )) })
16568
+ ] }) });
16569
+ }
16570
+
16571
+ function TracesToolbar({
16572
+ onClear,
16573
+ onRemoveAll,
16574
+ onSave,
16575
+ onRemoveSaved,
16576
+ isLoading,
16577
+ filterFields,
16578
+ filterTokens,
16579
+ onFilterTokensChange,
16580
+ autoFocusFilterFieldId
16581
+ }) {
16582
+ const hasActiveFilters = filterTokens.length > 0;
16583
+ const hasNonDefaultFilter = filterTokens.some((token) => isNonDefaultFilter$1(token, filterFields));
16584
+ return (
16585
+ // 1fr | auto — pills wrap in the first column; Clear stays pinned to the
16586
+ // top of the second column regardless of how many pill rows render.
16587
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("grid grid-cols-[1fr_auto] gap-3 items-start "), children: [
16588
+ /* @__PURE__ */ jsxRuntime.jsx(
16589
+ PropertyFilterApplied,
16590
+ {
16591
+ fields: filterFields,
16592
+ tokens: filterTokens,
16593
+ onTokensChange: onFilterTokensChange,
16594
+ disabled: isLoading,
16595
+ autoFocusFieldId: autoFocusFilterFieldId
16596
+ }
16597
+ ),
16598
+ hasActiveFilters && /* @__PURE__ */ jsxRuntime.jsx(
16599
+ PropertyFilterActions,
16600
+ {
16601
+ disabled: isLoading,
16602
+ onClear: hasNonDefaultFilter ? onClear : void 0,
16603
+ onRemoveAll,
16604
+ onSave,
16605
+ onRemoveSaved
16606
+ }
16607
+ )
16608
+ ] })
16609
+ );
16610
+ }
16611
+ function isNonDefaultFilter$1(token, fields) {
16612
+ const field = fields.find((f) => f.id === token.fieldId);
16613
+ if (!field) return false;
16614
+ if (field.kind === "text") {
16615
+ return typeof token.value === "string" && token.value.trim() !== "";
16616
+ }
16617
+ if (field.kind === "pick-multi") {
16618
+ if (field.multi) return Array.isArray(token.value) && token.value.length > 0;
16619
+ return typeof token.value === "string" && token.value !== "" && token.value !== "Any";
16620
+ }
16621
+ if (field.kind === "multi-select") {
16622
+ return Array.isArray(token.value) && token.value.length > 0;
16623
+ }
16624
+ return false;
16625
+ }
16626
+
16627
+ function TraceDataPanelView({
16628
+ traceId,
16629
+ spans,
16630
+ isLoading,
16631
+ onClose,
16632
+ onSpanSelect,
16633
+ onEvaluateTrace,
16634
+ onSaveAsDatasetItem,
16635
+ initialSpanId,
16636
+ onPrevious,
16637
+ onNext,
16638
+ collapsed: controlledCollapsed,
16639
+ onCollapsedChange,
16640
+ placement,
16641
+ timelineChartWidth = "default",
16642
+ LinkComponent,
16643
+ traceHref
16644
+ }) {
16645
+ const isOnTracePage = placement === "trace-page";
16646
+ const [internalCollapsed, setInternalCollapsed] = React.useState(false);
16647
+ const collapsed = controlledCollapsed ?? internalCollapsed;
16648
+ const setCollapsed = onCollapsedChange ?? setInternalCollapsed;
16649
+ const contentRef = React.useRef(null);
16650
+ const [selectedSpanId, setSelectedSpanId] = React.useState(initialSpanId ?? void 0);
16651
+ React.useEffect(() => {
16652
+ if (!initialSpanId) {
16653
+ setSelectedSpanId(void 0);
16654
+ onSpanSelect?.(void 0);
16655
+ return;
16656
+ }
16657
+ if (!spans) return;
16658
+ const found = spans.find((s) => s.spanId === initialSpanId);
16659
+ if (found) {
16660
+ setSelectedSpanId(initialSpanId);
16661
+ onSpanSelect?.(initialSpanId);
16662
+ } else {
16663
+ setSelectedSpanId(void 0);
16664
+ onSpanSelect?.(void 0);
16665
+ }
16666
+ }, [initialSpanId, spans]);
16667
+ React.useEffect(() => {
16668
+ if (!selectedSpanId || !contentRef.current) return;
16669
+ const el = contentRef.current.querySelector(`[data-span-id="${selectedSpanId}"]`);
16670
+ el?.scrollIntoView({ block: "nearest" });
16671
+ }, [selectedSpanId]);
16672
+ const hierarchicalSpans = React.useMemo(() => formatHierarchicalSpans(spans ?? []), [spans]);
16673
+ const [expandedSpanIds, setExpandedSpanIds] = React.useState([]);
16674
+ React.useEffect(() => {
16675
+ if (hierarchicalSpans.length > 0) {
16676
+ setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));
16677
+ }
16678
+ }, [hierarchicalSpans]);
16679
+ const rootSpan = React.useMemo(() => spans?.find((s) => s.parentSpanId == null), [spans]);
16680
+ const handleSpanClick = (id) => {
16681
+ const newId = selectedSpanId === id ? void 0 : id;
16682
+ setSelectedSpanId(newId);
16683
+ onSpanSelect?.(newId);
16684
+ };
16685
+ const showOpenTracePageLink = !isOnTracePage && LinkComponent && traceHref;
16686
+ return /* @__PURE__ */ jsxRuntime.jsxs(DataPanel, { collapsed, children: [
16687
+ /* @__PURE__ */ jsxRuntime.jsx(DataPanel.Header, { children: isOnTracePage ? /* @__PURE__ */ jsxRuntime.jsx(DataPanel.Heading, { children: "Trace Timeline" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16688
+ /* @__PURE__ */ jsxRuntime.jsxs(DataPanel.Heading, { children: [
16689
+ "Trace ",
16690
+ /* @__PURE__ */ jsxRuntime.jsxs("b", { children: [
16691
+ "# ",
16692
+ truncateString(traceId, 12)
16693
+ ] })
16694
+ ] }),
16695
+ /* @__PURE__ */ jsxRuntime.jsxs(ButtonsGroup, { className: "ml-auto shrink-0", children: [
16696
+ onCollapsedChange && /* @__PURE__ */ jsxRuntime.jsx(
16697
+ ButtonWithTooltip,
16698
+ {
16699
+ size: "md",
16700
+ tooltipContent: collapsed ? "Expand panel" : "Collapse panel",
16701
+ onClick: () => setCollapsed(!collapsed),
16702
+ children: collapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDownIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsDownUpIcon, {})
16703
+ }
16704
+ ),
16705
+ /* @__PURE__ */ jsxRuntime.jsx(
16706
+ DataPanel.NextPrevNav,
16707
+ {
16708
+ onPrevious,
16709
+ onNext,
16710
+ previousLabel: "Previous trace",
16711
+ nextLabel: "Next trace"
16712
+ }
16713
+ ),
16714
+ showOpenTracePageLink && /* @__PURE__ */ jsxRuntime.jsx(
16715
+ ButtonWithTooltip,
16716
+ {
16717
+ as: LinkComponent,
16718
+ href: traceHref,
16719
+ size: "md",
16720
+ tooltipContent: "Open trace page",
16721
+ "aria-label": "Open trace page",
16722
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Link2Icon, {})
16723
+ }
16724
+ ),
16725
+ /* @__PURE__ */ jsxRuntime.jsx(DataPanel.CloseButton, { onClick: onClose })
16726
+ ] })
16727
+ ] }) }),
16728
+ !collapsed && (isLoading ? /* @__PURE__ */ jsxRuntime.jsx(DataPanel.LoadingData, { children: "Loading trace..." }) : hierarchicalSpans.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(DataPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsxRuntime.jsxs(DataPanel.Content, { ref: contentRef, children: [
16729
+ !isOnTracePage && rootSpan && /* @__PURE__ */ jsxRuntime.jsx(TraceKeysAndValues, { rootSpan, className: "mb-6" }),
16730
+ !isOnTracePage && (onEvaluateTrace || onSaveAsDatasetItem) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6 flex justify-between items-center gap-4", children: [
16731
+ onEvaluateTrace && /* @__PURE__ */ jsxRuntime.jsxs(Button, { size: "sm", onClick: onEvaluateTrace, children: [
16732
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleGaugeIcon, {}) }),
16733
+ "Evaluate Trace"
16734
+ ] }),
16735
+ onSaveAsDatasetItem && /* @__PURE__ */ jsxRuntime.jsxs(Button, { size: "sm", onClick: () => onSaveAsDatasetItem({ traceId, rootSpanId: rootSpan?.spanId }), children: [
16736
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SaveIcon, {}) }),
16737
+ "Save as Dataset Item"
16738
+ ] })
16739
+ ] }),
16740
+ /* @__PURE__ */ jsxRuntime.jsx(
16741
+ TraceTimeline,
16742
+ {
16743
+ hierarchicalSpans,
16744
+ onSpanClick: handleSpanClick,
16745
+ selectedSpanId,
16746
+ expandedSpanIds,
16747
+ setExpandedSpanIds,
16748
+ chartWidth: timelineChartWidth
16749
+ }
16750
+ )
16751
+ ] }))
16752
+ ] });
16753
+ }
16754
+
16755
+ function getInputPreview(input, maxLength = 100) {
16756
+ if (input == null) return "";
16757
+ const messageArray = Array.isArray(input) ? input : input && typeof input === "object" && !Array.isArray(input) && Array.isArray(input.messages) ? input.messages : null;
16758
+ if (messageArray) {
16759
+ const messages = messageArray;
16760
+ const userMessages = messages.filter((m) => m?.role === "user").map((m) => {
16761
+ if (typeof m.content === "string") return m.content;
16762
+ if (Array.isArray(m.content)) {
16763
+ return m.content.map((part) => {
16764
+ if (typeof part === "string") return part;
16765
+ if (part?.type === "text" && typeof part.text === "string") return part.text;
16766
+ return "";
16767
+ }).filter(Boolean).join(" ");
16768
+ }
16769
+ return "";
16770
+ }).filter(Boolean);
16771
+ const joined = userMessages.join(" | ");
16772
+ if (joined.length > maxLength) {
16773
+ return joined.slice(0, maxLength) + "…";
16774
+ }
16775
+ return joined;
16776
+ }
16777
+ if (typeof input === "string") {
16778
+ if (input.length > maxLength) {
16779
+ return input.slice(0, maxLength) + "…";
16780
+ }
16781
+ return input;
16782
+ }
16783
+ const str = JSON.stringify(input);
16784
+ if (str.length > maxLength) {
16785
+ return str.slice(0, maxLength) + "…";
16786
+ }
16787
+ return str;
16788
+ }
16789
+ function isTokenLimitExceeded(span) {
16790
+ return span?.attributes?.finishReason === "length";
16791
+ }
16792
+ function getTokenLimitMessage(span) {
16793
+ const usage = span?.attributes?.usage;
16794
+ if (!usage) {
16795
+ return `The model stopped generating because it reached the maximum token limit. The response was truncated and may be incomplete.`;
16796
+ }
16797
+ const inputTokens = usage.inputTokens ?? 0;
16798
+ const outputTokens = usage.outputTokens ?? 0;
16799
+ const totalTokens = usage.totalTokens ?? inputTokens + outputTokens;
16800
+ if (inputTokens > 0 || outputTokens > 0) {
16801
+ return `The model stopped generating because it reached the maximum token limit. The response was truncated and may be incomplete.
16802
+
16803
+ Token usage: ${inputTokens} input + ${outputTokens} output = ${totalTokens} total`;
16804
+ }
16805
+ return `The model stopped generating because it reached the maximum token limit (${totalTokens} tokens). The response was truncated and may be incomplete.`;
16806
+ }
16807
+
16808
+ function buildDialogTitle(sectionTitle, icon, span) {
16809
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16810
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 text-neutral2 uppercase tracking-widest [&>svg]:size-3.5", children: [
16811
+ icon,
16812
+ sectionTitle
16813
+ ] }),
16814
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
16815
+ "› Span ",
16816
+ /* @__PURE__ */ jsxRuntime.jsxs("b", { className: "text-neutral3", children: [
16817
+ "#",
16818
+ span.spanId
16819
+ ] })
16820
+ ] }),
16821
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
16822
+ "› Trace ",
16823
+ /* @__PURE__ */ jsxRuntime.jsxs("b", { className: "text-neutral3", children: [
16824
+ "#",
16825
+ span.traceId
16826
+ ] })
16827
+ ] })
16828
+ ] });
16829
+ }
16830
+ function SpanDataPanelView({
16831
+ traceId,
16832
+ spanId,
16833
+ span,
16834
+ isLoading,
16835
+ onClose,
16836
+ onPrevious,
16837
+ onNext,
16838
+ activeTab,
16839
+ onTabChange,
16840
+ scoringTabSlot,
16841
+ scoringTabBadge
16842
+ }) {
16843
+ return /* @__PURE__ */ jsxRuntime.jsxs(DataPanel, { children: [
16844
+ /* @__PURE__ */ jsxRuntime.jsxs(DataPanel.Header, { children: [
16845
+ /* @__PURE__ */ jsxRuntime.jsxs(DataPanel.Heading, { children: [
16846
+ "Span ",
16847
+ /* @__PURE__ */ jsxRuntime.jsxs("b", { children: [
16848
+ "# ",
16849
+ spanId
16850
+ ] })
16851
+ ] }),
16852
+ /* @__PURE__ */ jsxRuntime.jsxs(ButtonsGroup, { className: "ml-auto shrink-0", children: [
16853
+ /* @__PURE__ */ jsxRuntime.jsx(
16854
+ DataPanel.NextPrevNav,
16855
+ {
16856
+ onPrevious,
16857
+ onNext,
16858
+ previousLabel: "Previous span",
16859
+ nextLabel: "Next span"
16860
+ }
16861
+ ),
16862
+ /* @__PURE__ */ jsxRuntime.jsx(DataPanel.CloseButton, { onClick: onClose })
16863
+ ] })
16864
+ ] }),
16865
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(DataPanel.LoadingData, { children: "Loading span details..." }) : !span ? /* @__PURE__ */ jsxRuntime.jsx(DataPanel.NoData, { children: "Span not found." }) : /* @__PURE__ */ jsxRuntime.jsx(
16866
+ SpanDataPanelContent,
16867
+ {
16868
+ span,
16869
+ traceId,
16870
+ spanId,
16871
+ activeTab,
16872
+ onTabChange,
16873
+ scoringTabSlot,
16874
+ scoringTabBadge
16875
+ }
16876
+ )
16877
+ ] });
16878
+ }
16879
+ function SpanDataPanelContent({
16880
+ span,
16881
+ traceId,
16882
+ spanId,
16883
+ activeTab,
16884
+ onTabChange,
16885
+ scoringTabSlot,
16886
+ scoringTabBadge
16887
+ }) {
16888
+ const durationMs = span.startedAt && span.endedAt ? new Date(span.endedAt).getTime() - new Date(span.startedAt).getTime() : null;
16889
+ const usage = span.attributes?.usage;
16890
+ const detailsBody = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16891
+ isTokenLimitExceeded(span) && /* @__PURE__ */ jsxRuntime.jsxs(Alert, { variant: "warning", className: "mb-3", children: [
16892
+ /* @__PURE__ */ jsxRuntime.jsx(AlertTitle, { children: "Token Limit Exceeded" }),
16893
+ /* @__PURE__ */ jsxRuntime.jsx(AlertDescription, { as: "p", children: getTokenLimitMessage(span) })
16894
+ ] }),
16895
+ usage && /* @__PURE__ */ jsxRuntime.jsx(SpanTokenUsage, { usage, className: "mb-3" }),
16896
+ /* @__PURE__ */ jsxRuntime.jsxs(DataKeysAndValues, { children: [
16897
+ span.parentSpanId == null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16898
+ span.traceId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16899
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Trace Id" }),
16900
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.ValueWithCopyBtn, { copyTooltip: "Copy Trace Id to clipboard", copyValue: span.traceId, children: span.traceId })
16901
+ ] }),
16902
+ span.tags && span.tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16903
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Tags" }),
16904
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: span.tags.join(", ") })
16905
+ ] }),
16906
+ span.runId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16907
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Run Id" }),
16908
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.ValueWithCopyBtn, { copyTooltip: "Copy Run Id to clipboard", copyValue: span.runId, children: span.runId })
16909
+ ] }),
16910
+ span.threadId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16911
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Thread Id" }),
16912
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.ValueWithCopyBtn, { copyTooltip: "Copy Thread Id to clipboard", copyValue: span.threadId, children: span.threadId })
16913
+ ] }),
16914
+ span.sessionId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16915
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Session Id" }),
16916
+ /* @__PURE__ */ jsxRuntime.jsx(
16917
+ DataKeysAndValues.ValueWithCopyBtn,
16918
+ {
16919
+ copyTooltip: "Copy Session Id to clipboard",
16920
+ copyValue: span.sessionId,
16921
+ children: span.sessionId
16922
+ }
16923
+ )
16924
+ ] }),
16925
+ span.requestId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16926
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Request Id" }),
16927
+ /* @__PURE__ */ jsxRuntime.jsx(
16928
+ DataKeysAndValues.ValueWithCopyBtn,
16929
+ {
16930
+ copyTooltip: "Copy Request Id to clipboard",
16931
+ copyValue: span.requestId,
16932
+ children: span.requestId
16933
+ }
16934
+ )
16935
+ ] }),
16936
+ span.resourceId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16937
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Resource Id" }),
16938
+ /* @__PURE__ */ jsxRuntime.jsx(
16939
+ DataKeysAndValues.ValueWithCopyBtn,
16940
+ {
16941
+ copyTooltip: "Copy Resource Id to clipboard",
16942
+ copyValue: span.resourceId,
16943
+ children: span.resourceId
16944
+ }
16945
+ )
16946
+ ] }),
16947
+ span.userId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16948
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "User Id" }),
16949
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.ValueWithCopyBtn, { copyTooltip: "Copy User Id to clipboard", copyValue: span.userId, children: span.userId })
16950
+ ] }),
16951
+ span.organizationId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16952
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Organization Id" }),
16953
+ /* @__PURE__ */ jsxRuntime.jsx(
16954
+ DataKeysAndValues.ValueWithCopyBtn,
16955
+ {
16956
+ copyTooltip: "Copy Organization Id to clipboard",
16957
+ copyValue: span.organizationId,
16958
+ children: span.organizationId
16959
+ }
16960
+ )
16961
+ ] }),
16962
+ span.experimentId && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16963
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Experiment Id" }),
16964
+ /* @__PURE__ */ jsxRuntime.jsx(
16965
+ DataKeysAndValues.ValueWithCopyBtn,
16966
+ {
16967
+ copyTooltip: "Copy Experiment Id to clipboard",
16968
+ copyValue: span.experimentId,
16969
+ children: span.experimentId
16970
+ }
16971
+ )
16972
+ ] })
16973
+ ] }),
16974
+ span.name && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16975
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Name" }),
16976
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: span.name })
16977
+ ] }),
16978
+ span.spanType && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16979
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Type" }),
16980
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: span.spanType })
16981
+ ] }),
16982
+ span.startedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16983
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Started" }),
16984
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: dateFns.format(new Date(span.startedAt), "MMM dd, HH:mm:ss.SSS") })
16985
+ ] }),
16986
+ span.endedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16987
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Ended" }),
16988
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: dateFns.format(new Date(span.endedAt), "MMM dd, HH:mm:ss.SSS") })
16989
+ ] }),
16990
+ durationMs != null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16991
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Key, { children: "Duration" }),
16992
+ /* @__PURE__ */ jsxRuntime.jsx(DataKeysAndValues.Value, { children: durationMs < 1e3 ? `${durationMs}ms` : `${(durationMs / 1e3).toFixed(2)}s` })
16993
+ ] })
16994
+ ] }),
16995
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-3 mt-3", children: [
16996
+ /* @__PURE__ */ jsxRuntime.jsx(
16997
+ DataPanel.CodeSection,
16998
+ {
16999
+ title: "Input",
17000
+ dialogTitle: buildDialogTitle("Input", /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileInputIcon, {}), { spanId, traceId }),
17001
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileInputIcon, {}),
17002
+ codeStr: JSON.stringify(span.input ?? null, null, 2)
17003
+ }
17004
+ ),
17005
+ /* @__PURE__ */ jsxRuntime.jsx(
17006
+ DataPanel.CodeSection,
17007
+ {
17008
+ title: "Output",
17009
+ dialogTitle: buildDialogTitle("Output", /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileOutputIcon, {}), { spanId, traceId }),
17010
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileOutputIcon, {}),
17011
+ codeStr: JSON.stringify(span.output ?? null, null, 2)
17012
+ }
17013
+ ),
17014
+ /* @__PURE__ */ jsxRuntime.jsx(
17015
+ DataPanel.CodeSection,
17016
+ {
17017
+ title: "Metadata",
17018
+ dialogTitle: buildDialogTitle("Metadata", /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BracesIcon, {}), { spanId, traceId }),
17019
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BracesIcon, {}),
17020
+ codeStr: JSON.stringify(span.metadata ?? null, null, 2)
17021
+ }
17022
+ ),
17023
+ /* @__PURE__ */ jsxRuntime.jsx(
17024
+ DataPanel.CodeSection,
17025
+ {
17026
+ title: "Attributes",
17027
+ dialogTitle: buildDialogTitle("Attributes", /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BracesIcon, {}), { spanId, traceId }),
17028
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BracesIcon, {}),
17029
+ codeStr: JSON.stringify(span.attributes ?? null, null, 2)
17030
+ }
17031
+ )
17032
+ ] })
17033
+ ] });
17034
+ if (!scoringTabSlot) {
17035
+ return /* @__PURE__ */ jsxRuntime.jsx(DataPanel.Content, { children: detailsBody });
17036
+ }
17037
+ return /* @__PURE__ */ jsxRuntime.jsx(DataPanel.Content, { children: /* @__PURE__ */ jsxRuntime.jsxs(Tabs, { defaultTab: "details", value: activeTab, onValueChange: onTabChange, children: [
17038
+ /* @__PURE__ */ jsxRuntime.jsxs(TabList, { children: [
17039
+ /* @__PURE__ */ jsxRuntime.jsx(Tab, { value: "details", children: "Details" }),
17040
+ /* @__PURE__ */ jsxRuntime.jsxs(Tab, { value: "scoring", children: [
17041
+ "Scoring ",
17042
+ scoringTabBadge != null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17043
+ "(",
17044
+ scoringTabBadge,
17045
+ ")"
17046
+ ] })
17047
+ ] })
17048
+ ] }),
17049
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "details", children: detailsBody }),
17050
+ /* @__PURE__ */ jsxRuntime.jsx(TabContent, { value: "scoring", children: scoringTabSlot({ span, traceId, spanId }) })
17051
+ ] }) });
17052
+ }
17053
+
17054
+ const KV$1 = DataDetailsPanel.KeyValueList;
17055
+ function SpanDetailsView({ spanId, span, isLoading, onClose }) {
17056
+ const durationMs = span?.startedAt && span?.endedAt ? new Date(span.endedAt).getTime() - new Date(span.startedAt).getTime() : null;
17057
+ return /* @__PURE__ */ jsxRuntime.jsxs(DataDetailsPanel, { children: [
17058
+ /* @__PURE__ */ jsxRuntime.jsxs(DataDetailsPanel.Header, { children: [
17059
+ /* @__PURE__ */ jsxRuntime.jsxs(DataDetailsPanel.Heading, { children: [
17060
+ "Span ",
17061
+ /* @__PURE__ */ jsxRuntime.jsxs("b", { children: [
17062
+ "# ",
17063
+ spanId
17064
+ ] })
17065
+ ] }),
17066
+ /* @__PURE__ */ jsxRuntime.jsx(DataDetailsPanel.CloseButton, { onClick: onClose })
17067
+ ] }),
17068
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(DataDetailsPanel.LoadingData, { children: "Loading span..." }) : !span ? /* @__PURE__ */ jsxRuntime.jsx(DataDetailsPanel.NoData, { children: "Span not found." }) : /* @__PURE__ */ jsxRuntime.jsxs(DataDetailsPanel.Content, { children: [
17069
+ /* @__PURE__ */ jsxRuntime.jsxs(KV$1, { children: [
17070
+ span.spanType && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17071
+ /* @__PURE__ */ jsxRuntime.jsx(KV$1.Key, { children: "Type" }),
17072
+ /* @__PURE__ */ jsxRuntime.jsx(KV$1.Value, { children: span.spanType })
17073
+ ] }),
17074
+ span.startedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17075
+ /* @__PURE__ */ jsxRuntime.jsx(KV$1.Key, { children: "Started" }),
17076
+ /* @__PURE__ */ jsxRuntime.jsx(KV$1.Value, { children: dateFns.format(new Date(span.startedAt), "MMM dd, HH:mm:ss.SSS") })
17077
+ ] }),
17078
+ span.endedAt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17079
+ /* @__PURE__ */ jsxRuntime.jsx(KV$1.Key, { children: "Ended" }),
17080
+ /* @__PURE__ */ jsxRuntime.jsx(KV$1.Value, { children: dateFns.format(new Date(span.endedAt), "MMM dd, HH:mm:ss.SSS") })
17081
+ ] }),
17082
+ durationMs != null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17083
+ /* @__PURE__ */ jsxRuntime.jsx(KV$1.Key, { children: "Duration" }),
17084
+ /* @__PURE__ */ jsxRuntime.jsx(KV$1.Value, { children: durationMs < 1e3 ? `${durationMs}ms` : `${(durationMs / 1e3).toFixed(2)}s` })
17085
+ ] })
17086
+ ] }),
17087
+ /* @__PURE__ */ jsxRuntime.jsx("br", {}),
17088
+ /* @__PURE__ */ jsxRuntime.jsx(
17089
+ DataDetailsPanel.CodeSection,
17090
+ {
17091
+ title: "Input",
17092
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileInputIcon, {}),
17093
+ codeStr: JSON.stringify(span.input ?? null, null, 2)
17094
+ }
17095
+ ),
17096
+ /* @__PURE__ */ jsxRuntime.jsx(
17097
+ DataDetailsPanel.CodeSection,
17098
+ {
17099
+ title: "Output",
17100
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileOutputIcon, {}),
17101
+ codeStr: JSON.stringify(span.output ?? null, null, 2)
17102
+ }
17103
+ ),
17104
+ /* @__PURE__ */ jsxRuntime.jsx(
17105
+ DataDetailsPanel.CodeSection,
17106
+ {
17107
+ title: "Metadata",
17108
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BracesIcon, {}),
17109
+ codeStr: JSON.stringify(span.metadata ?? null, null, 2)
17110
+ }
17111
+ ),
17112
+ /* @__PURE__ */ jsxRuntime.jsx(
17113
+ DataDetailsPanel.CodeSection,
17114
+ {
17115
+ title: "Attributes",
17116
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BracesIcon, {}),
17117
+ codeStr: JSON.stringify(span.attributes ?? null, null, 2)
17118
+ }
17119
+ )
17120
+ ] })
17121
+ ] });
17122
+ }
17123
+
17124
+ function TraceDetailsView({
17125
+ traceId,
17126
+ spans,
17127
+ isLoading,
17128
+ onClose,
17129
+ onSpanSelect,
17130
+ selectedSpanId
17131
+ }) {
17132
+ const hierarchicalSpans = React.useMemo(() => formatHierarchicalSpans(spans ?? []), [spans]);
17133
+ const [expandedSpanIds, setExpandedSpanIds] = React.useState([]);
17134
+ React.useEffect(() => {
17135
+ if (hierarchicalSpans.length > 0) {
17136
+ setExpandedSpanIds(getAllSpanIds(hierarchicalSpans));
17137
+ }
17138
+ }, [hierarchicalSpans]);
17139
+ const handleSpanClick = (id) => {
17140
+ onSpanSelect?.(selectedSpanId === id ? void 0 : id);
17141
+ };
17142
+ return /* @__PURE__ */ jsxRuntime.jsxs(DataDetailsPanel, { children: [
17143
+ /* @__PURE__ */ jsxRuntime.jsxs(DataDetailsPanel.Header, { children: [
17144
+ /* @__PURE__ */ jsxRuntime.jsxs(DataDetailsPanel.Heading, { children: [
17145
+ "Trace ",
17146
+ /* @__PURE__ */ jsxRuntime.jsxs("b", { children: [
17147
+ "# ",
17148
+ traceId
17149
+ ] })
17150
+ ] }),
17151
+ /* @__PURE__ */ jsxRuntime.jsx(DataDetailsPanel.CloseButton, { onClick: onClose })
17152
+ ] }),
17153
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(DataDetailsPanel.LoadingData, { children: "Loading trace..." }) : hierarchicalSpans.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(DataDetailsPanel.NoData, { children: "No spans found for this trace." }) : /* @__PURE__ */ jsxRuntime.jsx(DataDetailsPanel.Content, { children: /* @__PURE__ */ jsxRuntime.jsx(
17154
+ TraceTimeline,
17155
+ {
17156
+ hierarchicalSpans,
17157
+ onSpanClick: handleSpanClick,
17158
+ selectedSpanId: selectedSpanId ?? void 0,
17159
+ expandedSpanIds,
17160
+ setExpandedSpanIds
17161
+ }
17162
+ ) })
17163
+ ] });
17164
+ }
17165
+
17166
+ function TracesLayout({
17167
+ listSlot,
17168
+ tracePanelSlot,
17169
+ spanPanelSlot,
17170
+ scorePanelSlot,
17171
+ traceCollapsed
17172
+ }) {
17173
+ const hasSidePanel = !!tracePanelSlot;
17174
+ return /* @__PURE__ */ jsxRuntime.jsxs(
17175
+ "div",
17176
+ {
17177
+ className: cn(
17178
+ "grid max-h-full min-h-0 gap-4 items-start ",
17179
+ hasSidePanel ? "grid-cols-[1fr_1fr]" : "grid-cols-[1fr]"
17180
+ ),
17181
+ children: [
17182
+ listSlot,
17183
+ hasSidePanel && /* @__PURE__ */ jsxRuntime.jsxs(
17184
+ "div",
17185
+ {
17186
+ className: cn(
17187
+ "grid gap-4 max-h-full overflow-auto",
17188
+ scorePanelSlot ? traceCollapsed ? "grid-rows-[auto_3fr_3fr]" : "grid-rows-[2fr_3fr_3fr]" : spanPanelSlot ? traceCollapsed ? "grid-rows-[auto_3fr]" : "grid-rows-[2fr_3fr]" : traceCollapsed ? "grid-rows-[auto]" : "grid-rows-[1fr]"
17189
+ ),
17190
+ children: [
17191
+ tracePanelSlot,
17192
+ spanPanelSlot,
17193
+ scorePanelSlot
17194
+ ]
17195
+ }
17196
+ )
17197
+ ]
17198
+ }
17199
+ );
17200
+ }
17201
+
17202
+ function groupTracesByThread(traces) {
17203
+ const threadMap = /* @__PURE__ */ new Map();
17204
+ const ungrouped = [];
17205
+ for (const trace of traces) {
17206
+ if (trace.threadId) {
17207
+ const existing = threadMap.get(trace.threadId);
17208
+ if (existing) {
17209
+ existing.push(trace);
17210
+ } else {
17211
+ threadMap.set(trace.threadId, [trace]);
17212
+ }
17213
+ } else {
17214
+ ungrouped.push(trace);
17215
+ }
17216
+ }
17217
+ const groups = Array.from(threadMap.entries()).map(([threadId, traces2]) => ({
17218
+ threadId,
17219
+ traces: traces2
17220
+ }));
17221
+ groups.sort((a, b) => {
17222
+ const aLatest = Math.max(...a.traces.map((t) => new Date(t.createdAt).getTime()));
17223
+ const bLatest = Math.max(...b.traces.map((t) => new Date(t.createdAt).getTime()));
17224
+ return bLatest - aLatest;
17225
+ });
17226
+ return { groups, ungrouped };
17227
+ }
17228
+
17229
+ const COLUMNS$1 = "auto auto auto auto minmax(5rem,1fr) auto auto";
17230
+ function TracesListView({
17231
+ traces,
17232
+ isLoading,
17233
+ isFetchingNextPage,
17234
+ hasNextPage,
17235
+ setEndOfListElement,
17236
+ filtersApplied,
17237
+ featuredTraceId,
17238
+ onTraceClick,
17239
+ groupByThread,
17240
+ threadTitles
17241
+ }) {
17242
+ if (isLoading) {
17243
+ return /* @__PURE__ */ jsxRuntime.jsx(DataListSkeleton, { columns: COLUMNS$1 });
17244
+ }
17245
+ const renderRows = (rows) => rows.map((trace) => {
17246
+ const isFeatured = trace.traceId === featuredTraceId;
17247
+ const displayDate = trace.startedAt ?? trace.createdAt;
17248
+ const entityName = trace.entityName || trace.entityId || trace.attributes?.agentId || trace.attributes?.workflowId;
17249
+ return /* @__PURE__ */ jsxRuntime.jsxs(
17250
+ TracesDataList.RowButton,
17251
+ {
17252
+ onClick: () => onTraceClick(trace),
17253
+ className: cn(isFeatured && "bg-surface4"),
17254
+ children: [
17255
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.IdCell, { traceId: trace.traceId }),
17256
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.DateCell, { timestamp: displayDate }),
17257
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.TimeCell, { timestamp: displayDate }),
17258
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.NameCell, { name: trace.name }),
17259
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.InputCell, { input: getInputPreview(trace.input) }),
17260
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.EntityCell, { entityType: trace.entityType, entityName }),
17261
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.StatusCell, { status: trace.attributes?.status })
17262
+ ]
17263
+ },
17264
+ trace.traceId
17265
+ );
17266
+ });
17267
+ return /* @__PURE__ */ jsxRuntime.jsxs(TracesDataList, { columns: COLUMNS$1, className: "min-w-0", children: [
17268
+ /* @__PURE__ */ jsxRuntime.jsxs(TracesDataList.Top, { children: [
17269
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.TopCell, { children: "ID" }),
17270
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.TopCell, { children: "Date" }),
17271
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.TopCell, { children: "Time" }),
17272
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.TopCell, { children: "Name" }),
17273
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.TopCell, { children: "Input" }),
17274
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.TopCell, { children: "Entity" }),
17275
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.TopCell, { children: "Status" })
17276
+ ] }),
17277
+ traces.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
17278
+ TracesDataList.NoMatch,
17279
+ {
17280
+ message: filtersApplied ? "No traces found for applied filters" : "No traces found yet"
17281
+ }
17282
+ ) : groupByThread ? (() => {
17283
+ const { groups, ungrouped } = groupTracesByThread(traces);
17284
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17285
+ groups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
17286
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.Subheader, { children: /* @__PURE__ */ jsxRuntime.jsxs(TracesDataList.SubHeading, { className: "flex gap-2", children: [
17287
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "uppercase", children: "Thread" }),
17288
+ threadTitles?.[group.threadId] && /* @__PURE__ */ jsxRuntime.jsxs("b", { children: [
17289
+ "'",
17290
+ threadTitles[group.threadId],
17291
+ "'"
17292
+ ] }),
17293
+ /* @__PURE__ */ jsxRuntime.jsxs("b", { children: [
17294
+ "# ",
17295
+ group.threadId
17296
+ ] }),
17297
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-neutral2", children: [
17298
+ "(",
17299
+ group.traces.length,
17300
+ ")"
17301
+ ] })
17302
+ ] }) }),
17303
+ renderRows(group.traces)
17304
+ ] }, group.threadId)),
17305
+ ungrouped.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17306
+ /* @__PURE__ */ jsxRuntime.jsx(TracesDataList.Subheader, { children: /* @__PURE__ */ jsxRuntime.jsxs(TracesDataList.SubHeading, { className: "flex gap-2 uppercase", children: [
17307
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "No thread" }),
17308
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-neutral2", children: [
17309
+ "(",
17310
+ ungrouped.length,
17311
+ ")"
17312
+ ] })
17313
+ ] }) }),
17314
+ renderRows(ungrouped)
17315
+ ] })
17316
+ ] });
17317
+ })() : renderRows(traces),
17318
+ traces.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
17319
+ TracesDataList.NextPageLoading,
17320
+ {
17321
+ isLoading: isFetchingNextPage,
17322
+ hasMore: hasNextPage,
17323
+ setEndOfListElement
17324
+ }
17325
+ )
17326
+ ] });
17327
+ }
17328
+
17329
+ function TracesErrorContent({ error, resource, errorTitle }) {
17330
+ if (is401UnauthorizedError(error)) return /* @__PURE__ */ jsxRuntime.jsx(SessionExpired, {});
17331
+ if (is403ForbiddenError(error)) return /* @__PURE__ */ jsxRuntime.jsx(PermissionDenied, { resource });
17332
+ const parsed = error instanceof Error ? parseError(error) : void 0;
17333
+ return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { title: errorTitle, message: parsed?.error ?? "Unknown error" });
17334
+ }
17335
+
17336
+ const IMMUTABLE_CACHE_TIME$1 = 1e3 * 60 * 60 * 24 * 30;
17337
+ function useSpanDetail(traceId, spanId) {
17338
+ const client = react.useMastraClient();
17339
+ return reactQuery.useQuery({
17340
+ queryKey: ["span-detail", traceId, spanId],
17341
+ queryFn: async () => {
17342
+ if (!traceId || !spanId) {
17343
+ throw new Error("Trace ID and Span ID are required");
17344
+ }
17345
+ return client.getSpan(traceId, spanId);
17346
+ },
17347
+ enabled: !!traceId && !!spanId,
17348
+ staleTime: (query) => {
17349
+ const data = query.state.data;
17350
+ if (data?.span?.endedAt) {
17351
+ return IMMUTABLE_CACHE_TIME$1;
17352
+ }
17353
+ return 0;
17354
+ }
17355
+ });
17356
+ }
17357
+
17358
+ const IMMUTABLE_CACHE_TIME = 1e3 * 60 * 60 * 24 * 30;
17359
+ function useTraceLightSpans(traceId) {
17360
+ const client = react.useMastraClient();
17361
+ return reactQuery.useQuery({
17362
+ queryKey: ["trace-light-spans", traceId],
17363
+ queryFn: async () => {
17364
+ if (!traceId) {
17365
+ throw new Error("Trace ID is required");
17366
+ }
17367
+ const res = await client.getTraceLight(traceId);
17368
+ return res;
17369
+ },
17370
+ enabled: !!traceId,
17371
+ staleTime: (query) => {
17372
+ const data = query.state.data;
17373
+ const isFinished = data?.spans.every((d) => Boolean(d.endedAt));
17374
+ if (isFinished) {
17375
+ return IMMUTABLE_CACHE_TIME;
17376
+ }
17377
+ return 0;
17378
+ }
17379
+ });
17380
+ }
17381
+
17382
+ function useTraceSpans(traceId) {
17383
+ const client = react.useMastraClient();
17384
+ return reactQuery.useQuery({
17385
+ queryKey: ["trace-spans", traceId],
17386
+ queryFn: async () => {
17387
+ if (!traceId) {
17388
+ throw new Error("Trace ID is required");
17389
+ }
17390
+ const res = await client.getTrace(traceId);
17391
+ return res;
17392
+ },
17393
+ enabled: !!traceId
17394
+ });
17395
+ }
17396
+
17397
+ const fetchTracesFn = async ({
17398
+ client,
17399
+ page,
17400
+ perPage,
17401
+ filters
17402
+ }) => {
17403
+ return client.listTraces({
17404
+ pagination: {
17405
+ page,
17406
+ perPage
17407
+ },
17408
+ filters
17409
+ });
17410
+ };
17411
+ const TRACES_PER_PAGE = 25;
17412
+ function getTracesNextPageParam(lastPage, _allPages, lastPageParam) {
17413
+ if (lastPage?.pagination?.hasMore) {
17414
+ return lastPageParam + 1;
17415
+ }
17416
+ return void 0;
17417
+ }
17418
+ function selectUniqueTraces(data) {
17419
+ const seen = /* @__PURE__ */ new Set();
17420
+ const spans = data.pages.flatMap((page) => page.spans ?? []).filter((span) => {
17421
+ if (seen.has(span.traceId)) return false;
17422
+ seen.add(span.traceId);
17423
+ return true;
17424
+ });
17425
+ const threadTitles = {};
17426
+ for (const page of data.pages) {
17427
+ if (page.threadTitles) {
17428
+ Object.assign(threadTitles, page.threadTitles);
17429
+ }
17430
+ }
17431
+ return { spans, threadTitles };
17432
+ }
17433
+ const useTraces = ({ filters }) => {
17434
+ const client = react.useMastraClient();
17435
+ const { inView: isEndOfListInView, setRef: setEndOfListElement } = useInView();
17436
+ const query = reactQuery.useInfiniteQuery({
17437
+ queryKey: ["traces", filters],
17438
+ queryFn: ({ pageParam }) => fetchTracesFn({
17439
+ client,
17440
+ page: pageParam,
17441
+ perPage: TRACES_PER_PAGE,
17442
+ filters
17443
+ }),
17444
+ initialPageParam: 0,
17445
+ getNextPageParam: getTracesNextPageParam,
17446
+ select: selectUniqueTraces,
17447
+ placeholderData: reactQuery.keepPreviousData,
17448
+ retry: false,
17449
+ // Disable polling on 403 to prevent flickering
17450
+ refetchInterval: (query2) => is403ForbiddenError(query2.state.error) ? false : 3e3
17451
+ });
17452
+ const { hasNextPage, isFetchingNextPage, fetchNextPage } = query;
17453
+ React.useEffect(() => {
17454
+ if (isEndOfListInView && hasNextPage && !isFetchingNextPage) {
17455
+ void fetchNextPage();
17456
+ }
17457
+ }, [isEndOfListInView, hasNextPage, isFetchingNextPage, fetchNextPage]);
17458
+ return { ...query, setEndOfListElement };
17459
+ };
17460
+
17461
+ const useTags = () => {
17462
+ const client = react.useMastraClient();
17463
+ return reactQuery.useQuery({
17464
+ queryKey: ["observability-tags"],
17465
+ queryFn: async () => {
17466
+ try {
17467
+ return await client.getTags();
17468
+ } catch {
17469
+ return { tags: [] };
17470
+ }
17471
+ },
17472
+ select: (data) => data?.tags ?? [],
17473
+ retry: false
17474
+ });
17475
+ };
17476
+
17477
+ const ROOT_ENTITY_TYPES = {
17478
+ AGENT: observability.EntityType.AGENT,
17479
+ WORKFLOW: observability.EntityType.WORKFLOW_RUN,
17480
+ SCORER: observability.EntityType.SCORER,
17481
+ INGEST: observability.EntityType.RAG_INGESTION
17482
+ };
17483
+ const ROOT_ENTITY_TYPE_OPTIONS = [
17484
+ { label: "Agent", entityType: ROOT_ENTITY_TYPES.AGENT },
17485
+ { label: "Workflow", entityType: ROOT_ENTITY_TYPES.WORKFLOW },
17486
+ { label: "Scorer", entityType: ROOT_ENTITY_TYPES.SCORER },
17487
+ { label: "Ingest", entityType: ROOT_ENTITY_TYPES.INGEST }
17488
+ ];
17489
+ const TRACE_STATUS_OPTIONS = [
17490
+ { label: "Running", value: "running" },
17491
+ { label: "Success", value: "success" },
17492
+ { label: "Error", value: "error" }
17493
+ ];
17494
+ const TRACE_SYNTHETIC_FILTER_FIELD_IDS = ["rootEntityType", "status"];
17495
+ const TRACE_ROOT_ENTITY_TYPE_PARAM = "rootEntityType";
17496
+ const TRACE_STATUS_PARAM = "status";
17497
+ const TRACE_DATE_PRESET_PARAM = "datePreset";
17498
+ const TRACE_DATE_FROM_PARAM = "dateFrom";
17499
+ const TRACE_DATE_TO_PARAM = "dateTo";
17500
+ const TRACE_DATE_PRESET_VALUES = /* @__PURE__ */ new Set([
17501
+ "all",
17502
+ "last-24h",
17503
+ "last-3d",
17504
+ "last-7d",
17505
+ "last-14d",
17506
+ "last-30d",
17507
+ "custom"
17508
+ ]);
17509
+ const TRACE_PROPERTY_FILTER_PARAM_BY_FIELD = {
17510
+ tags: "filterTags",
17511
+ entityId: "filterEntityId",
17512
+ entityName: "filterEntityName",
17513
+ traceId: "filterTraceId",
17514
+ runId: "filterRunId",
17515
+ threadId: "filterThreadId",
17516
+ sessionId: "filterSessionId",
17517
+ requestId: "filterRequestId",
17518
+ resourceId: "filterResourceId",
17519
+ userId: "filterUserId",
17520
+ organizationId: "filterOrganizationId",
17521
+ serviceName: "filterServiceName",
17522
+ environment: "filterEnvironment",
17523
+ experimentId: "filterExperimentId"
17524
+ };
17525
+ const TRACE_PROPERTY_FILTER_FIELD_IDS = Object.keys(TRACE_PROPERTY_FILTER_PARAM_BY_FIELD);
17526
+ const TRACE_STATUS_VALUES = /* @__PURE__ */ new Set(["running", "success", "error"]);
17527
+ const DEFAULT_TRACE_FILTERS_STORAGE_KEY = "mastra:traces:saved-filters";
17528
+ function saveTraceFiltersToStorage(params, storageKey = DEFAULT_TRACE_FILTERS_STORAGE_KEY) {
17529
+ const serialized = getPreservedTraceFilterParams(params);
17530
+ const preset = params.get(TRACE_DATE_PRESET_PARAM);
17531
+ if (preset) serialized.set(TRACE_DATE_PRESET_PARAM, preset);
17532
+ const from = params.get(TRACE_DATE_FROM_PARAM);
17533
+ if (from) serialized.set(TRACE_DATE_FROM_PARAM, from);
17534
+ const to = params.get(TRACE_DATE_TO_PARAM);
17535
+ if (to) serialized.set(TRACE_DATE_TO_PARAM, to);
17536
+ try {
17537
+ localStorage.setItem(storageKey, serialized.toString());
17538
+ } catch {
17539
+ }
17540
+ }
17541
+ function clearSavedTraceFilters(storageKey = DEFAULT_TRACE_FILTERS_STORAGE_KEY) {
17542
+ try {
17543
+ localStorage.removeItem(storageKey);
17544
+ } catch {
17545
+ }
17546
+ }
17547
+ function loadTraceFiltersFromStorage(storageKey = DEFAULT_TRACE_FILTERS_STORAGE_KEY) {
17548
+ try {
17549
+ const raw = localStorage.getItem(storageKey);
17550
+ if (!raw) return null;
17551
+ const parsed = new URLSearchParams(raw);
17552
+ return parsed.toString() ? parsed : null;
17553
+ } catch {
17554
+ return null;
17555
+ }
17556
+ }
17557
+ function hasAnyTraceFilterParams(params) {
17558
+ if (params.has(TRACE_DATE_PRESET_PARAM)) return true;
17559
+ if (params.has(TRACE_DATE_FROM_PARAM)) return true;
17560
+ if (params.has(TRACE_DATE_TO_PARAM)) return true;
17561
+ if (params.has(TRACE_ROOT_ENTITY_TYPE_PARAM)) return true;
17562
+ if (params.has(TRACE_STATUS_PARAM)) return true;
17563
+ for (const fieldId of TRACE_PROPERTY_FILTER_FIELD_IDS) {
17564
+ if (params.has(TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId])) return true;
17565
+ }
17566
+ return false;
17567
+ }
17568
+ function createTracePropertyFilterFields({
17569
+ availableTags,
17570
+ availableRootEntityNames,
17571
+ availableServiceNames,
17572
+ availableEnvironments,
17573
+ loading
17574
+ }) {
17575
+ const fields = [
17576
+ {
17577
+ id: "rootEntityType",
17578
+ label: "Primitive Type",
17579
+ kind: "pick-multi",
17580
+ searchable: false,
17581
+ options: ROOT_ENTITY_TYPE_OPTIONS.map((o) => ({ label: o.label, value: o.entityType })),
17582
+ placeholder: "Choose entity type",
17583
+ emptyText: "No entity types."
17584
+ },
17585
+ {
17586
+ id: "entityName",
17587
+ label: "Primitive Name",
17588
+ kind: "pick-multi",
17589
+ options: availableRootEntityNames.map((name) => ({ label: name, value: name })),
17590
+ placeholder: "Choose entity names",
17591
+ emptyText: "No entity names found.",
17592
+ isLoading: loading?.entityNames
17593
+ },
17594
+ { id: "entityId", label: "Primitive ID", kind: "text" },
17595
+ {
17596
+ id: "status",
17597
+ label: "Status",
17598
+ kind: "pick-multi",
17599
+ searchable: false,
17600
+ options: TRACE_STATUS_OPTIONS.map((o) => ({ label: o.label, value: o.value })),
17601
+ placeholder: "Choose status",
17602
+ emptyText: "No statuses."
17603
+ },
17604
+ {
17605
+ id: "tags",
17606
+ label: "Tags",
17607
+ kind: "pick-multi",
17608
+ multi: true,
17609
+ options: availableTags.map((tag) => ({ label: tag, value: tag })),
17610
+ placeholder: "Choose tags",
17611
+ emptyText: "No tags found.",
17612
+ isLoading: loading?.tags
17613
+ },
17614
+ {
17615
+ id: "serviceName",
17616
+ label: "Service Name",
17617
+ kind: "pick-multi",
17618
+ options: availableServiceNames.map((name) => ({ label: name, value: name })),
17619
+ placeholder: "Choose service names",
17620
+ emptyText: "No service names found.",
17621
+ isLoading: loading?.serviceNames
17622
+ },
17623
+ {
17624
+ id: "environment",
17625
+ label: "Environment",
17626
+ kind: "pick-multi",
17627
+ options: availableEnvironments.map((env) => ({ label: env, value: env })),
17628
+ placeholder: "Choose environments",
17629
+ emptyText: "No environments found.",
17630
+ isLoading: loading?.environments
17631
+ },
17632
+ { id: "traceId", label: "Trace ID", kind: "text" },
17633
+ { id: "runId", label: "Run ID", kind: "text" },
17634
+ { id: "threadId", label: "Thread ID", kind: "text" },
17635
+ { id: "sessionId", label: "Session ID", kind: "text" },
17636
+ { id: "requestId", label: "Request ID", kind: "text" },
17637
+ { id: "resourceId", label: "Resource ID", kind: "text" },
17638
+ { id: "userId", label: "User ID", kind: "text" },
17639
+ { id: "organizationId", label: "Organization ID", kind: "text" },
17640
+ { id: "experimentId", label: "Experiment ID", kind: "text" }
17641
+ ];
17642
+ const byLabel = (a, b) => a.label.localeCompare(b.label);
17643
+ const pickMulti = fields.filter((f) => f.kind === "pick-multi").sort(byLabel);
17644
+ const text = fields.filter((f) => f.kind === "text").sort(byLabel);
17645
+ return [...pickMulti, ...text];
17646
+ }
17647
+ function getTracePropertyFilterTokens(searchParams) {
17648
+ const tokens = [];
17649
+ const paramToFieldId = /* @__PURE__ */ new Map([
17650
+ [TRACE_ROOT_ENTITY_TYPE_PARAM, "rootEntityType"],
17651
+ [TRACE_STATUS_PARAM, "status"]
17652
+ ]);
17653
+ for (const fieldId of TRACE_PROPERTY_FILTER_FIELD_IDS) {
17654
+ paramToFieldId.set(TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId], fieldId);
17655
+ }
17656
+ const seen = /* @__PURE__ */ new Set();
17657
+ for (const [paramName] of searchParams.entries()) {
17658
+ const fieldId = paramToFieldId.get(paramName);
17659
+ if (!fieldId || seen.has(fieldId)) continue;
17660
+ seen.add(fieldId);
17661
+ if (fieldId === "tags") {
17662
+ const raw = searchParams.getAll(paramName);
17663
+ if (raw.length === 0) continue;
17664
+ tokens.push({ fieldId, value: raw.filter(Boolean) });
17665
+ continue;
17666
+ }
17667
+ const value = searchParams.get(paramName);
17668
+ if (value !== null) tokens.push({ fieldId, value });
17669
+ }
17670
+ return tokens;
17671
+ }
17672
+ function getPreservedTraceFilterParams(searchParams) {
17673
+ const next = new URLSearchParams();
17674
+ const rootEntityType = searchParams.get(TRACE_ROOT_ENTITY_TYPE_PARAM);
17675
+ if (rootEntityType) next.set(TRACE_ROOT_ENTITY_TYPE_PARAM, rootEntityType);
17676
+ const status = searchParams.get(TRACE_STATUS_PARAM);
17677
+ if (status) next.set(TRACE_STATUS_PARAM, status);
17678
+ for (const fieldId of TRACE_PROPERTY_FILTER_FIELD_IDS) {
17679
+ const param = TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId];
17680
+ if (fieldId === "tags") {
17681
+ for (const value2 of searchParams.getAll(param)) {
17682
+ next.append(param, value2);
17683
+ }
17684
+ continue;
17685
+ }
17686
+ const value = searchParams.get(param);
17687
+ if (value) {
17688
+ next.set(param, value);
17689
+ }
17690
+ }
17691
+ return next;
17692
+ }
17693
+ function applyTracePropertyFilterTokens(params, tokens) {
17694
+ params.delete(TRACE_ROOT_ENTITY_TYPE_PARAM);
17695
+ params.delete(TRACE_STATUS_PARAM);
17696
+ for (const fieldId of TRACE_PROPERTY_FILTER_FIELD_IDS) {
17697
+ params.delete(TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId]);
17698
+ }
17699
+ for (const token of tokens) {
17700
+ if (token.fieldId === "rootEntityType" && typeof token.value === "string") {
17701
+ params.set(TRACE_ROOT_ENTITY_TYPE_PARAM, token.value);
17702
+ continue;
17703
+ }
17704
+ if (token.fieldId === "status" && typeof token.value === "string") {
17705
+ params.set(TRACE_STATUS_PARAM, token.value);
17706
+ continue;
17707
+ }
17708
+ const param = TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[token.fieldId];
17709
+ if (!param) continue;
17710
+ if (token.fieldId === "tags" && Array.isArray(token.value)) {
17711
+ if (token.value.length === 0) {
17712
+ params.append(param, "");
17713
+ } else {
17714
+ for (const value of token.value) {
17715
+ params.append(param, value);
17716
+ }
17717
+ }
17718
+ continue;
17719
+ }
17720
+ if (typeof token.value === "string") {
17721
+ params.set(param, token.value.trim());
17722
+ }
17723
+ }
17724
+ }
17725
+ function buildTraceListFilters({
17726
+ rootEntityType,
17727
+ status,
17728
+ dateFrom,
17729
+ dateTo,
17730
+ tokens
17731
+ }) {
17732
+ const filters = {};
17733
+ if (rootEntityType) {
17734
+ filters.entityType = rootEntityType;
17735
+ }
17736
+ if (status) {
17737
+ filters.status = status;
17738
+ }
17739
+ if (dateFrom) {
17740
+ filters.startedAt = { start: dateFrom };
17741
+ }
17742
+ if (dateTo) {
17743
+ filters.endedAt = { end: dateTo };
17744
+ }
17745
+ for (const token of tokens) {
17746
+ if (token.fieldId === "tags") {
17747
+ if (Array.isArray(token.value) && token.value.length > 0) {
17748
+ filters.tags = token.value;
17749
+ } else if (typeof token.value === "string" && token.value.trim()) {
17750
+ filters.tags = [token.value.trim()];
17751
+ }
17752
+ continue;
17753
+ }
17754
+ if (typeof token.value !== "string") continue;
17755
+ if (!token.value.trim()) continue;
17756
+ if (token.value === "Any") continue;
17757
+ switch (token.fieldId) {
17758
+ case "entityId":
17759
+ filters.entityId = token.value;
17760
+ break;
17761
+ case "entityName":
17762
+ filters.entityName = token.value;
17763
+ break;
17764
+ case "traceId":
17765
+ filters.traceId = token.value;
17766
+ break;
17767
+ case "runId":
17768
+ filters.runId = token.value;
17769
+ break;
17770
+ case "threadId":
17771
+ filters.threadId = token.value;
17772
+ break;
17773
+ case "sessionId":
17774
+ filters.sessionId = token.value;
17775
+ break;
17776
+ case "requestId":
17777
+ filters.requestId = token.value;
17778
+ break;
17779
+ case "resourceId":
17780
+ filters.resourceId = token.value;
17781
+ break;
17782
+ case "userId":
17783
+ filters.userId = token.value;
17784
+ break;
17785
+ case "organizationId":
17786
+ filters.organizationId = token.value;
17787
+ break;
17788
+ case "serviceName":
17789
+ filters.serviceName = token.value;
17790
+ break;
17791
+ case "environment":
17792
+ filters.environment = token.value;
17793
+ break;
17794
+ case "experimentId":
17795
+ filters.experimentId = token.value;
17796
+ break;
17797
+ }
17798
+ }
17799
+ return filters;
17800
+ }
17801
+ function neutralizeFilterTokens(filterFields, filterTokens) {
17802
+ return filterTokens.map((token) => {
17803
+ const field = filterFields.find((f) => f.id === token.fieldId);
17804
+ if (!field) return token;
17805
+ if (field.kind === "text") return { fieldId: token.fieldId, value: "" };
17806
+ if (field.kind === "pick-multi") {
17807
+ return field.multi ? { fieldId: token.fieldId, value: [] } : { fieldId: token.fieldId, value: "Any" };
17808
+ }
17809
+ return token;
17810
+ });
17811
+ }
17812
+
17813
+ const useEntityNames = ({ entityType, rootOnly = false } = {}) => {
17814
+ const client = react.useMastraClient();
17815
+ const queryKey = entityType ? ["observability-entity-names", "by-type", entityType] : ["observability-entity-names", "all", rootOnly ? "root-only" : "all-types"];
17816
+ return reactQuery.useQuery({
17817
+ queryKey,
17818
+ queryFn: async () => {
17819
+ try {
17820
+ if (entityType) {
17821
+ return await client.getEntityNames({ entityType });
17822
+ }
17823
+ if (!rootOnly) {
17824
+ return await client.getEntityNames();
17825
+ }
17826
+ const responses = await Promise.all(
17827
+ ROOT_ENTITY_TYPE_OPTIONS.map((option) => client.getEntityNames({ entityType: option.entityType }))
17828
+ );
17829
+ return {
17830
+ names: Array.from(new Set(responses.flatMap((response) => response?.names ?? []))).sort()
17831
+ };
17832
+ } catch {
17833
+ return { names: [] };
17834
+ }
17835
+ },
17836
+ select: (data) => data?.names ?? [],
17837
+ retry: false
17838
+ });
17839
+ };
17840
+
17841
+ const useEnvironments = () => {
17842
+ const client = react.useMastraClient();
17843
+ return reactQuery.useQuery({
17844
+ queryKey: ["observability-environments"],
17845
+ queryFn: async () => {
17846
+ try {
17847
+ return await client.getEnvironments();
17848
+ } catch {
17849
+ return { environments: [] };
17850
+ }
17851
+ },
17852
+ select: (data) => data?.environments ?? [],
17853
+ retry: false
17854
+ });
17855
+ };
17856
+
17857
+ const useServiceNames = () => {
17858
+ const client = react.useMastraClient();
17859
+ return reactQuery.useQuery({
17860
+ queryKey: ["observability-service-names"],
17861
+ queryFn: async () => {
17862
+ try {
17863
+ return await client.getServiceNames();
17864
+ } catch {
17865
+ return { serviceNames: [] };
17866
+ }
17867
+ },
17868
+ select: (data) => data?.serviceNames ?? [],
17869
+ retry: false
17870
+ });
17871
+ };
17872
+
17873
+ function useTraceSpanNavigation(lightSpans, featuredSpanId, onSpanChange) {
17874
+ const timelineSpanIds = React.useMemo(() => getAllSpanIds(formatHierarchicalSpans(lightSpans ?? [])), [lightSpans]);
17875
+ const featuredSpanIdx = featuredSpanId ? timelineSpanIds.indexOf(featuredSpanId) : -1;
17876
+ const handlePreviousSpan = featuredSpanIdx > 0 ? () => onSpanChange(timelineSpanIds[featuredSpanIdx - 1]) : void 0;
17877
+ const handleNextSpan = featuredSpanIdx >= 0 && featuredSpanIdx < timelineSpanIds.length - 1 ? () => onSpanChange(timelineSpanIds[featuredSpanIdx + 1]) : void 0;
17878
+ return { handlePreviousSpan, handleNextSpan, timelineSpanIds };
17879
+ }
17880
+
17881
+ function useTraceListNavigation(traces, featuredTraceId, onTraceChange) {
17882
+ const featuredTraceIdx = React.useMemo(
17883
+ () => featuredTraceId ? traces.findIndex((t) => t.traceId === featuredTraceId) : -1,
17884
+ [traces, featuredTraceId]
17885
+ );
17886
+ const handlePreviousTrace = featuredTraceIdx > 0 ? () => onTraceChange(traces[featuredTraceIdx - 1].traceId) : void 0;
17887
+ const handleNextTrace = featuredTraceIdx >= 0 && featuredTraceIdx < traces.length - 1 ? () => onTraceChange(traces[featuredTraceIdx + 1].traceId) : void 0;
17888
+ return { featuredTraceIdx, handlePreviousTrace, handleNextTrace };
17889
+ }
17890
+
17891
+ const TRACE_ID_PARAM = "traceId";
17892
+ const SPAN_ID_PARAM = "spanId";
17893
+ const TAB_PARAM = "tab";
17894
+ const SCORE_ID_PARAM = "scoreId";
17895
+ const DAY_MS$1 = 24 * 60 * 60 * 1e3;
17896
+ const PRESET_MS$1 = {
17897
+ "last-24h": DAY_MS$1,
17898
+ "last-3d": 3 * DAY_MS$1,
17899
+ "last-7d": 7 * DAY_MS$1,
17900
+ "last-14d": 14 * DAY_MS$1,
17901
+ "last-30d": 30 * DAY_MS$1
17902
+ };
17903
+ function clearSelectionParams$1(params) {
17904
+ params.delete(TRACE_ID_PARAM);
17905
+ params.delete(SPAN_ID_PARAM);
17906
+ params.delete(TAB_PARAM);
17907
+ params.delete(SCORE_ID_PARAM);
17908
+ }
17909
+ function useTraceUrlState(searchParams, setSearchParams, options) {
17910
+ const { onRemoveAll } = options ?? {};
17911
+ const datePreset = React.useMemo(() => {
17912
+ const value = searchParams.get(TRACE_DATE_PRESET_PARAM);
17913
+ return value && TRACE_DATE_PRESET_VALUES.has(value) ? value : "last-24h";
17914
+ }, [searchParams]);
17915
+ const dateFromParamRaw = searchParams.get(TRACE_DATE_FROM_PARAM);
17916
+ const dateToParamRaw = searchParams.get(TRACE_DATE_TO_PARAM);
17917
+ const selectedDateFrom = React.useMemo(() => {
17918
+ if (datePreset === "custom") {
17919
+ if (!dateFromParamRaw) return void 0;
17920
+ const parsed = new Date(dateFromParamRaw);
17921
+ return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
17922
+ }
17923
+ if (datePreset === "all") return void 0;
17924
+ const ms = PRESET_MS$1[datePreset];
17925
+ return ms ? new Date(Date.now() - ms) : void 0;
17926
+ }, [datePreset, dateFromParamRaw]);
17927
+ const selectedDateTo = React.useMemo(() => {
17928
+ if (datePreset !== "custom" || !dateToParamRaw) return void 0;
17929
+ const parsed = new Date(dateToParamRaw);
17930
+ return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
17931
+ }, [datePreset, dateToParamRaw]);
17932
+ const datePresetRef = React.useRef(datePreset);
17933
+ datePresetRef.current = datePreset;
17934
+ const traceIdParam = searchParams.get(TRACE_ID_PARAM) || void 0;
17935
+ const spanIdParam = searchParams.get(SPAN_ID_PARAM) || void 0;
17936
+ const tabParam = searchParams.get(TAB_PARAM);
17937
+ const spanTabParam = tabParam === "scoring" ? "scoring" : tabParam === "details" ? "details" : void 0;
17938
+ const scoreIdParam = searchParams.get(SCORE_ID_PARAM) || void 0;
17939
+ const selectedEntityOption = React.useMemo(
17940
+ () => ROOT_ENTITY_TYPE_OPTIONS.find((option) => option.entityType === searchParams.get(TRACE_ROOT_ENTITY_TYPE_PARAM)),
17941
+ [searchParams]
17942
+ );
17943
+ const selectedStatus = React.useMemo(() => {
17944
+ const value = searchParams.get(TRACE_STATUS_PARAM);
17945
+ return value && TRACE_STATUS_VALUES.has(value) ? value : void 0;
17946
+ }, [searchParams]);
17947
+ const filterTokens = React.useMemo(() => getTracePropertyFilterTokens(searchParams), [searchParams]);
17948
+ const handleTraceClick = React.useCallback(
17949
+ (traceId) => {
17950
+ setSearchParams(
17951
+ (prev) => {
17952
+ const next = new URLSearchParams(prev);
17953
+ if (traceId) {
17954
+ next.set(TRACE_ID_PARAM, traceId);
17955
+ } else {
17956
+ next.delete(TRACE_ID_PARAM);
17957
+ }
17958
+ next.delete(SPAN_ID_PARAM);
17959
+ next.delete(TAB_PARAM);
17960
+ next.delete(SCORE_ID_PARAM);
17961
+ return next;
17962
+ },
17963
+ { replace: true }
17964
+ );
17965
+ },
17966
+ [setSearchParams]
17967
+ );
17968
+ const handleTraceClose = React.useCallback(() => handleTraceClick(""), [handleTraceClick]);
17969
+ const handleSpanChange = React.useCallback(
17970
+ (spanId) => {
17971
+ const currentSpanId = searchParams.get(SPAN_ID_PARAM) || null;
17972
+ if (spanId === currentSpanId) return;
17973
+ setSearchParams(
17974
+ (prev) => {
17975
+ const next = new URLSearchParams(prev);
17976
+ if (spanId) {
17977
+ next.set(SPAN_ID_PARAM, spanId);
17978
+ } else {
17979
+ next.delete(SPAN_ID_PARAM);
17980
+ }
17981
+ next.delete(TAB_PARAM);
17982
+ next.delete(SCORE_ID_PARAM);
17983
+ return next;
17984
+ },
17985
+ { replace: true }
17986
+ );
17987
+ },
17988
+ [searchParams, setSearchParams]
17989
+ );
17990
+ const handleSpanClose = React.useCallback(() => handleSpanChange(null), [handleSpanChange]);
17991
+ const handleSpanTabChange = React.useCallback(
17992
+ (tab) => {
17993
+ const currentTab = searchParams.get(TAB_PARAM) || null;
17994
+ if (tab === currentTab) return;
17995
+ setSearchParams(
17996
+ (prev) => {
17997
+ const next = new URLSearchParams(prev);
17998
+ if (tab && tab !== "details") {
17999
+ next.set(TAB_PARAM, tab);
18000
+ } else {
18001
+ next.delete(TAB_PARAM);
18002
+ }
18003
+ next.delete(SCORE_ID_PARAM);
18004
+ return next;
18005
+ },
18006
+ { replace: true }
18007
+ );
18008
+ },
18009
+ [searchParams, setSearchParams]
18010
+ );
18011
+ const handleScoreChange = React.useCallback(
18012
+ (scoreId) => {
18013
+ const currentScoreId = searchParams.get(SCORE_ID_PARAM) || null;
18014
+ if (scoreId === currentScoreId) return;
18015
+ setSearchParams(
18016
+ (prev) => {
18017
+ const next = new URLSearchParams(prev);
18018
+ if (scoreId) {
18019
+ next.set(SCORE_ID_PARAM, scoreId);
18020
+ } else {
18021
+ next.delete(SCORE_ID_PARAM);
18022
+ }
18023
+ return next;
18024
+ },
18025
+ { replace: true }
18026
+ );
18027
+ },
18028
+ [searchParams, setSearchParams]
18029
+ );
18030
+ const applyFilterTokens = React.useCallback(
18031
+ (tokens) => {
18032
+ setSearchParams(
18033
+ (prev) => {
18034
+ const next = new URLSearchParams(prev);
18035
+ applyTracePropertyFilterTokens(next, tokens);
18036
+ clearSelectionParams$1(next);
18037
+ return next;
18038
+ },
18039
+ { replace: true }
18040
+ );
18041
+ },
18042
+ [setSearchParams]
18043
+ );
18044
+ const handleFilterTokensChange = applyFilterTokens;
18045
+ const handleDateChange = React.useCallback(
18046
+ (value, type) => {
18047
+ if (datePresetRef.current !== "custom") return;
18048
+ const param = type === "from" ? TRACE_DATE_FROM_PARAM : TRACE_DATE_TO_PARAM;
18049
+ setSearchParams(
18050
+ (prev) => {
18051
+ const next = new URLSearchParams(prev);
18052
+ if (value) {
18053
+ next.set(param, value.toISOString());
18054
+ } else {
18055
+ next.delete(param);
18056
+ }
18057
+ clearSelectionParams$1(next);
18058
+ return next;
18059
+ },
18060
+ { replace: true }
18061
+ );
18062
+ },
18063
+ [setSearchParams]
18064
+ );
18065
+ const handleDatePresetChange = React.useCallback(
18066
+ (preset) => {
18067
+ datePresetRef.current = preset;
18068
+ setSearchParams(
18069
+ (prev) => {
18070
+ const next = new URLSearchParams(prev);
18071
+ if (preset === "last-24h") {
18072
+ next.delete(TRACE_DATE_PRESET_PARAM);
18073
+ next.delete(TRACE_DATE_FROM_PARAM);
18074
+ next.delete(TRACE_DATE_TO_PARAM);
18075
+ } else if (preset === "custom") {
18076
+ next.set(TRACE_DATE_PRESET_PARAM, "custom");
18077
+ } else {
18078
+ next.set(TRACE_DATE_PRESET_PARAM, preset);
18079
+ next.delete(TRACE_DATE_FROM_PARAM);
18080
+ next.delete(TRACE_DATE_TO_PARAM);
18081
+ }
18082
+ clearSelectionParams$1(next);
18083
+ return next;
18084
+ },
18085
+ { replace: true }
18086
+ );
18087
+ },
18088
+ [setSearchParams]
18089
+ );
18090
+ const handleRemoveAll = React.useCallback(() => {
18091
+ setSearchParams(
18092
+ (prev) => {
18093
+ const next = new URLSearchParams(prev);
18094
+ next.delete(TRACE_ROOT_ENTITY_TYPE_PARAM);
18095
+ next.delete(TRACE_STATUS_PARAM);
18096
+ for (const fieldId of TRACE_PROPERTY_FILTER_FIELD_IDS) {
18097
+ next.delete(TRACE_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId]);
18098
+ }
18099
+ clearSelectionParams$1(next);
18100
+ return next;
18101
+ },
18102
+ { replace: true }
18103
+ );
18104
+ onRemoveAll?.();
18105
+ }, [setSearchParams, onRemoveAll]);
18106
+ return {
18107
+ searchParams,
18108
+ setSearchParams,
18109
+ datePreset,
18110
+ selectedDateFrom,
18111
+ selectedDateTo,
18112
+ datePresetRef,
18113
+ traceIdParam,
18114
+ spanIdParam,
18115
+ spanTabParam,
18116
+ scoreIdParam,
18117
+ selectedEntityOption,
18118
+ selectedStatus,
18119
+ filterTokens,
18120
+ handleTraceClick,
18121
+ handleTraceClose,
18122
+ handleSpanChange,
18123
+ handleSpanClose,
18124
+ handleSpanTabChange,
18125
+ handleScoreChange,
18126
+ handleFilterTokensChange,
18127
+ handleDateChange,
18128
+ handleDatePresetChange,
18129
+ handleRemoveAll,
18130
+ applyFilterTokens
18131
+ };
18132
+ }
18133
+
18134
+ const DEFAULT_SAVED_MESSAGE$1 = "Trace filter settings saved.";
18135
+ const DEFAULT_CLEARED_MESSAGE$1 = "Trace filter settings cleared.";
18136
+ function useTraceFilterPersistence(searchParams, setSearchParams, options) {
18137
+ const { storageKey, messages, skipHydration } = options ?? {};
18138
+ const [hasSavedFilters, setHasSavedFilters] = React.useState(() => loadTraceFiltersFromStorage(storageKey) !== null);
18139
+ const handleSave = React.useCallback(() => {
18140
+ saveTraceFiltersToStorage(searchParams, storageKey);
18141
+ setHasSavedFilters(true);
18142
+ const text = messages?.saved ?? DEFAULT_SAVED_MESSAGE$1;
18143
+ if (text !== false) toast.success(text);
18144
+ }, [searchParams, storageKey, messages?.saved]);
18145
+ const handleRemoveSaved = React.useCallback(() => {
18146
+ clearSavedTraceFilters(storageKey);
18147
+ setHasSavedFilters(false);
18148
+ const text = messages?.cleared ?? DEFAULT_CLEARED_MESSAGE$1;
18149
+ if (text !== false) toast.success(text);
18150
+ }, [storageKey, messages?.cleared]);
18151
+ const hydratedRef = React.useRef(false);
18152
+ React.useEffect(() => {
18153
+ if (skipHydration) return;
18154
+ if (hydratedRef.current) return;
18155
+ hydratedRef.current = true;
18156
+ if (hasAnyTraceFilterParams(searchParams)) return;
18157
+ const saved = loadTraceFiltersFromStorage(storageKey);
18158
+ if (!saved) return;
18159
+ setSearchParams(
18160
+ (prev) => {
18161
+ const next = new URLSearchParams(prev);
18162
+ for (const [key, value] of saved) {
18163
+ next.append(key, value);
18164
+ }
18165
+ return next;
18166
+ },
18167
+ { replace: true }
18168
+ );
18169
+ }, []);
18170
+ return { hasSavedFilters, handleSave, handleRemoveSaved };
18171
+ }
18172
+
18173
+ const CONTEXT_FIELD_IDS = [
18174
+ "environment",
18175
+ "serviceName",
18176
+ "source",
18177
+ "scope",
18178
+ "userId",
18179
+ "organizationId",
18180
+ "resourceId",
18181
+ "runId",
18182
+ "sessionId",
18183
+ "threadId",
18184
+ "requestId",
18185
+ "experimentId",
18186
+ "spanType",
18187
+ "entityName",
18188
+ "parentEntityType",
18189
+ "parentEntityId",
18190
+ "parentEntityName",
18191
+ "rootEntityType",
18192
+ "rootEntityId",
18193
+ "rootEntityName"
18194
+ ];
18195
+
18196
+ const KV = DataDetailsPanel.KeyValueList;
18197
+ function toDate(value) {
18198
+ return value instanceof Date ? value : new Date(value);
18199
+ }
18200
+ function LogDetailsView({
18201
+ log,
18202
+ onClose,
18203
+ onTraceClick,
18204
+ onSpanClick,
18205
+ onPrevious,
18206
+ onNext,
18207
+ collapsed: controlledCollapsed,
18208
+ onCollapsedChange
18209
+ }) {
18210
+ const [internalCollapsed, setInternalCollapsed] = React.useState(false);
18211
+ const collapsed = controlledCollapsed ?? internalCollapsed;
18212
+ const setCollapsed = onCollapsedChange ?? setInternalCollapsed;
18213
+ const date = toDate(log.timestamp);
18214
+ return /* @__PURE__ */ jsxRuntime.jsxs(DataDetailsPanel, { collapsed, children: [
18215
+ /* @__PURE__ */ jsxRuntime.jsxs(DataDetailsPanel.Header, { children: [
18216
+ /* @__PURE__ */ jsxRuntime.jsxs(DataDetailsPanel.Heading, { children: [
18217
+ "Log ",
18218
+ /* @__PURE__ */ jsxRuntime.jsx("b", { children: dateFns.format(date, "MMM dd, HH:mm:ss.SSS") })
18219
+ ] }),
18220
+ /* @__PURE__ */ jsxRuntime.jsxs(ButtonsGroup, { className: "ml-auto shrink-0", children: [
18221
+ onCollapsedChange && /* @__PURE__ */ jsxRuntime.jsx(
18222
+ ButtonWithTooltip,
18223
+ {
18224
+ size: "md",
18225
+ tooltipContent: collapsed ? "Expand panel" : "Collapse panel",
18226
+ onClick: () => setCollapsed(!collapsed),
18227
+ children: collapsed ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDownIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsDownUpIcon, {})
18228
+ }
18229
+ ),
18230
+ /* @__PURE__ */ jsxRuntime.jsxs(ButtonsGroup, { spacing: "close", children: [
18231
+ /* @__PURE__ */ jsxRuntime.jsx(ButtonWithTooltip, { size: "md", tooltipContent: "Previous log", onClick: onPrevious, disabled: !onPrevious, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpIcon, {}) }),
18232
+ /* @__PURE__ */ jsxRuntime.jsx(ButtonWithTooltip, { size: "md", tooltipContent: "Next log", onClick: onNext, disabled: !onNext, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownIcon, {}) })
18233
+ ] }),
18234
+ /* @__PURE__ */ jsxRuntime.jsx(DataDetailsPanel.CloseButton, { onClick: onClose })
18235
+ ] })
18236
+ ] }),
18237
+ !collapsed && /* @__PURE__ */ jsxRuntime.jsxs(DataDetailsPanel.Content, { children: [
18238
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-ui-md text-neutral4 font-mono wrap-break-word whitespace-pre-wrap", children: log.message }),
18239
+ (log.traceId || log.spanId) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("grid gap-2 my-8", "[&>button]:justify-between [&>button]:overflow-hidden"), children: [
18240
+ log.traceId && /* @__PURE__ */ jsxRuntime.jsxs(ButtonsGroup, { spacing: "close", className: "min-w-0 w-full", children: [
18241
+ /* @__PURE__ */ jsxRuntime.jsxs(
18242
+ Button,
18243
+ {
18244
+ size: "md",
18245
+ className: "min-w-0 flex-1 overflow-hidden",
18246
+ onClick: () => onTraceClick?.(log.traceId),
18247
+ children: [
18248
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightIcon, {}),
18249
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Trace" }),
18250
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: " ml-auto text-ui-sm text-neutral2 min-w-0 truncate", children: [
18251
+ "# ",
18252
+ log.traceId
18253
+ ] })
18254
+ ]
18255
+ }
18256
+ ),
18257
+ /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { content: log.traceId, size: "md", tooltip: "Copy Trace ID to clipboard" })
18258
+ ] }),
18259
+ log.spanId && /* @__PURE__ */ jsxRuntime.jsxs(ButtonsGroup, { spacing: "close", className: "min-w-0 w-full", children: [
18260
+ /* @__PURE__ */ jsxRuntime.jsxs(
18261
+ Button,
18262
+ {
18263
+ size: "md",
18264
+ className: "min-w-0 flex-1 overflow-hidden",
18265
+ disabled: !log.traceId || !onSpanClick,
18266
+ onClick: () => log.traceId && onSpanClick?.(log.traceId, log.spanId),
18267
+ children: [
18268
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRightIcon, {}),
18269
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Span" }),
18270
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: " ml-auto text-ui-sm text-neutral2 min-w-0 truncate", children: [
18271
+ "# ",
18272
+ log.spanId
18273
+ ] })
18274
+ ]
18275
+ }
18276
+ ),
18277
+ /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { content: log.spanId, size: "md", tooltip: "Copy Span ID to clipboard" })
18278
+ ] })
18279
+ ] }),
18280
+ /* @__PURE__ */ jsxRuntime.jsxs(KV, { className: "mb-6", children: [
18281
+ log.entityType && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18282
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Key, { children: "Entity Type" }),
18283
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Value, { children: log.entityType })
18284
+ ] }),
18285
+ log.entityName && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18286
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Key, { children: "Entity Name" }),
18287
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Value, { children: log.entityName })
18288
+ ] }),
18289
+ log.serviceName && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18290
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Key, { children: "Service" }),
18291
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Value, { children: log.serviceName })
18292
+ ] }),
18293
+ log.environment && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18294
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Key, { children: "Environment" }),
18295
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Value, { children: log.environment })
18296
+ ] }),
18297
+ log.source && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
18298
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Key, { children: "Source" }),
18299
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Value, { children: log.source })
18300
+ ] }),
18301
+ log.metadata && Object.keys(log.metadata).length > 0 && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: Object.entries(log.metadata).map(([key, value]) => /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
18302
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Key, { children: key }),
18303
+ /* @__PURE__ */ jsxRuntime.jsx(KV.Value, { children: String(value) })
18304
+ ] }, key)) })
18305
+ ] }),
18306
+ log.data && Object.keys(log.data).length > 0 && /* @__PURE__ */ jsxRuntime.jsx(DataDetailsPanel.CodeSection, { title: "Data", codeStr: JSON.stringify(log.data, null, 2), className: "mt-6" })
18307
+ ] })
18308
+ ] });
18309
+ }
18310
+
18311
+ function LogsErrorContent({ error, resource, errorTitle }) {
18312
+ if (is401UnauthorizedError(error)) return /* @__PURE__ */ jsxRuntime.jsx(SessionExpired, {});
18313
+ if (is403ForbiddenError(error)) return /* @__PURE__ */ jsxRuntime.jsx(PermissionDenied, { resource });
18314
+ const message = error instanceof Error ? error.message : void 0;
18315
+ return /* @__PURE__ */ jsxRuntime.jsx(ErrorState, { title: errorTitle, message: message ?? "Unknown error" });
18316
+ }
18317
+
18318
+ function LogsLayout({ listSlot, logPanelSlot, tracePanelSlot, spanPanelSlot, logCollapsed }) {
18319
+ const hasSidePanel = !!logPanelSlot;
18320
+ return /* @__PURE__ */ jsxRuntime.jsxs(
18321
+ "div",
18322
+ {
18323
+ className: cn("grid h-full min-h-0 gap-4 items-start", hasSidePanel ? "grid-cols-[1fr_1fr]" : "grid-cols-[1fr]"),
18324
+ children: [
18325
+ listSlot,
18326
+ hasSidePanel && /* @__PURE__ */ jsxRuntime.jsxs(
18327
+ "div",
18328
+ {
18329
+ className: cn(
18330
+ "grid gap-4 h-full overflow-auto",
18331
+ tracePanelSlot && spanPanelSlot ? logCollapsed ? "grid-rows-[auto_1fr_1fr]" : "grid-rows-[1fr_1fr_1fr]" : tracePanelSlot ? logCollapsed ? "grid-rows-[auto_1fr]" : "grid-rows-[1fr_1fr]" : logCollapsed ? "grid-rows-[auto]" : "grid-rows-[1fr]"
18332
+ ),
18333
+ children: [
18334
+ logPanelSlot,
18335
+ tracePanelSlot,
18336
+ spanPanelSlot
18337
+ ]
18338
+ }
18339
+ )
18340
+ ]
18341
+ }
18342
+ );
18343
+ }
18344
+
18345
+ const COLUMNS = "auto auto auto auto minmax(5rem,1fr) minmax(5rem,1fr)";
18346
+ function LogsListView({
18347
+ logs,
18348
+ isLoading,
18349
+ isFetchingNextPage,
18350
+ hasNextPage,
18351
+ setEndOfListElement,
18352
+ logIdMap,
18353
+ featuredLogId,
18354
+ onLogClick
18355
+ }) {
18356
+ if (isLoading) {
18357
+ return /* @__PURE__ */ jsxRuntime.jsx(DataListSkeleton, { columns: COLUMNS });
18358
+ }
18359
+ return /* @__PURE__ */ jsxRuntime.jsxs(LogsDataList, { columns: COLUMNS, className: "min-w-0", children: [
18360
+ /* @__PURE__ */ jsxRuntime.jsxs(LogsDataList.Top, { children: [
18361
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.TopCell, { children: "Date" }),
18362
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.TopCell, { children: "Time" }),
18363
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.TopCell, { children: "Level" }),
18364
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.TopCell, { children: "Entity" }),
18365
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.TopCell, { children: "Message" }),
18366
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.TopCell, { children: "Data" })
18367
+ ] }),
18368
+ logs.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.NoMatch, { message: "No logs match your search" }) : logs.map((log) => {
18369
+ const id = logIdMap.get(log);
18370
+ if (!id) return null;
18371
+ const isFeatured = id === featuredLogId;
18372
+ return /* @__PURE__ */ jsxRuntime.jsxs(
18373
+ LogsDataList.RowButton,
18374
+ {
18375
+ onClick: () => onLogClick(log),
18376
+ className: cn(isFeatured && "bg-surface4"),
18377
+ children: [
18378
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.DateCell, { timestamp: log.timestamp }),
18379
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.TimeCell, { timestamp: log.timestamp }),
18380
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.LevelCell, { level: log.level }),
18381
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.EntityCell, { entityType: log.entityType, entityName: log.entityName }),
18382
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.MessageCell, { message: log.message }),
18383
+ /* @__PURE__ */ jsxRuntime.jsx(LogsDataList.DataCell, { data: log.data })
18384
+ ]
18385
+ },
18386
+ id
18387
+ );
18388
+ }),
18389
+ /* @__PURE__ */ jsxRuntime.jsx(
18390
+ LogsDataList.NextPageLoading,
18391
+ {
18392
+ isLoading: isFetchingNextPage,
18393
+ hasMore: hasNextPage,
18394
+ setEndOfListElement
18395
+ }
18396
+ )
18397
+ ] });
18398
+ }
18399
+
18400
+ function LogsToolbar({
18401
+ onClear,
18402
+ onRemoveAll,
18403
+ onSave,
18404
+ onRemoveSaved,
18405
+ isLoading,
18406
+ filterFields,
18407
+ filterTokens,
18408
+ onFilterTokensChange,
18409
+ autoFocusFilterFieldId
18410
+ }) {
18411
+ const hasActiveFilters = filterTokens.length > 0;
18412
+ const hasNonDefaultFilter = filterTokens.some((token) => isNonDefaultFilter(token, filterFields));
18413
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("grid grid-cols-[1fr_auto] gap-3 items-start"), children: [
18414
+ /* @__PURE__ */ jsxRuntime.jsx(
18415
+ PropertyFilterApplied,
18416
+ {
18417
+ fields: filterFields,
18418
+ tokens: filterTokens,
18419
+ onTokensChange: onFilterTokensChange,
18420
+ disabled: isLoading,
18421
+ autoFocusFieldId: autoFocusFilterFieldId
18422
+ }
18423
+ ),
18424
+ hasActiveFilters && /* @__PURE__ */ jsxRuntime.jsx(
18425
+ PropertyFilterActions,
18426
+ {
18427
+ disabled: isLoading,
18428
+ onClear: hasNonDefaultFilter ? onClear : void 0,
18429
+ onRemoveAll,
18430
+ onSave,
18431
+ onRemoveSaved
18432
+ }
18433
+ )
18434
+ ] });
18435
+ }
18436
+ function isNonDefaultFilter(token, fields) {
18437
+ const field = fields.find((f) => f.id === token.fieldId);
18438
+ if (!field) return false;
18439
+ if (field.kind === "text") {
18440
+ return typeof token.value === "string" && token.value.trim() !== "";
18441
+ }
18442
+ if (field.kind === "pick-multi") {
18443
+ if (field.multi) return Array.isArray(token.value) && token.value.length > 0;
18444
+ return typeof token.value === "string" && token.value !== "" && token.value !== "Any";
18445
+ }
18446
+ if (field.kind === "multi-select") {
18447
+ return Array.isArray(token.value) && token.value.length > 0;
18448
+ }
18449
+ return false;
18450
+ }
18451
+
18452
+ const NoLogsInfo = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
18453
+ EmptyState,
18454
+ {
18455
+ iconSlot: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleSlashIcon, {}),
18456
+ titleSlot: "No logs yet",
18457
+ descriptionSlot: "Logs will appear here once agents, workflows, or tools are executed."
18458
+ }
18459
+ ) });
18460
+
18461
+ const LOGS_PER_PAGE = 20;
18462
+ function getNextPageParam(lastPage, _allPages, lastPageParam) {
18463
+ if (lastPage?.pagination?.hasMore) {
18464
+ return lastPageParam + 1;
18465
+ }
18466
+ return void 0;
18467
+ }
18468
+ function selectLogs(data) {
18469
+ return data.pages.flatMap((page) => page.logs ?? []);
18470
+ }
18471
+ const useLogs = ({ filters } = {}) => {
18472
+ const client = react.useMastraClient();
18473
+ const { inView: isEndOfListInView, setRef: setEndOfListElement } = useInView();
18474
+ const query = reactQuery.useInfiniteQuery({
18475
+ queryKey: ["logs", filters],
18476
+ queryFn: ({ pageParam }) => client.listLogsVNext({
18477
+ pagination: { page: pageParam, perPage: LOGS_PER_PAGE },
18478
+ filters,
18479
+ orderBy: { field: "timestamp", direction: "DESC" }
18480
+ }),
18481
+ initialPageParam: 0,
18482
+ getNextPageParam,
18483
+ select: selectLogs,
18484
+ retry: false,
18485
+ refetchInterval: 3e3
18486
+ });
18487
+ const { hasNextPage, isFetchingNextPage, fetchNextPage } = query;
18488
+ React.useEffect(() => {
18489
+ if (isEndOfListInView && hasNextPage && !isFetchingNextPage) {
18490
+ void fetchNextPage();
18491
+ }
18492
+ }, [isEndOfListInView, hasNextPage, isFetchingNextPage, fetchNextPage]);
18493
+ return { ...query, data: query.data, setEndOfListElement };
18494
+ };
18495
+
18496
+ const LOGS_ROOT_ENTITY_TYPES = {
18497
+ AGENT: observability.EntityType.AGENT,
18498
+ WORKFLOW: observability.EntityType.WORKFLOW_RUN,
18499
+ SCORER: observability.EntityType.SCORER,
18500
+ INGEST: observability.EntityType.RAG_INGESTION
18501
+ };
18502
+ const LOGS_ROOT_ENTITY_TYPE_OPTIONS = [
18503
+ { label: "Agent", entityType: LOGS_ROOT_ENTITY_TYPES.AGENT },
18504
+ { label: "Workflow", entityType: LOGS_ROOT_ENTITY_TYPES.WORKFLOW },
18505
+ { label: "Scorer", entityType: LOGS_ROOT_ENTITY_TYPES.SCORER },
18506
+ { label: "Ingest", entityType: LOGS_ROOT_ENTITY_TYPES.INGEST }
18507
+ ];
18508
+ const LOG_LEVEL_VALUES = ["debug", "info", "warn", "error", "fatal"];
18509
+ const LOG_LEVEL_OPTIONS = [
18510
+ { label: "Debug", value: "debug" },
18511
+ { label: "Info", value: "info" },
18512
+ { label: "Warn", value: "warn" },
18513
+ { label: "Error", value: "error" },
18514
+ { label: "Fatal", value: "fatal" }
18515
+ ];
18516
+ const LOGS_ROOT_ENTITY_TYPE_PARAM = "rootEntityType";
18517
+ const LOGS_DATE_PRESET_PARAM = "datePreset";
18518
+ const LOGS_DATE_FROM_PARAM = "dateFrom";
18519
+ const LOGS_DATE_TO_PARAM = "dateTo";
18520
+ const LOGS_DATE_PRESET_VALUES = /* @__PURE__ */ new Set([
18521
+ "all",
18522
+ "last-24h",
18523
+ "last-3d",
18524
+ "last-7d",
18525
+ "last-14d",
18526
+ "last-30d",
18527
+ "custom"
18528
+ ]);
18529
+ const LOGS_PROPERTY_FILTER_PARAM_BY_FIELD = {
18530
+ level: "filterLevel",
18531
+ tags: "filterTags",
18532
+ entityName: "filterEntityName",
18533
+ traceId: "filterTraceId",
18534
+ spanId: "filterSpanId",
18535
+ runId: "filterRunId",
18536
+ threadId: "filterThreadId",
18537
+ sessionId: "filterSessionId",
18538
+ requestId: "filterRequestId",
18539
+ resourceId: "filterResourceId",
18540
+ userId: "filterUserId",
18541
+ organizationId: "filterOrganizationId",
18542
+ serviceName: "filterServiceName",
18543
+ environment: "filterEnvironment",
18544
+ experimentId: "filterExperimentId"
18545
+ };
18546
+ const LOGS_PROPERTY_FILTER_FIELD_IDS = Object.keys(LOGS_PROPERTY_FILTER_PARAM_BY_FIELD);
18547
+ const LOGS_ARRAY_FIELD_IDS = /* @__PURE__ */ new Set(["tags"]);
18548
+ const DEFAULT_LOGS_FILTERS_STORAGE_KEY = "mastra:logs:saved-filters";
18549
+ function saveLogsFiltersToStorage(params, storageKey = DEFAULT_LOGS_FILTERS_STORAGE_KEY) {
18550
+ const serialized = getPreservedLogsFilterParams(params);
18551
+ const preset = params.get(LOGS_DATE_PRESET_PARAM);
18552
+ if (preset) serialized.set(LOGS_DATE_PRESET_PARAM, preset);
18553
+ const from = params.get(LOGS_DATE_FROM_PARAM);
18554
+ if (from) serialized.set(LOGS_DATE_FROM_PARAM, from);
18555
+ const to = params.get(LOGS_DATE_TO_PARAM);
18556
+ if (to) serialized.set(LOGS_DATE_TO_PARAM, to);
18557
+ try {
18558
+ localStorage.setItem(storageKey, serialized.toString());
18559
+ } catch {
18560
+ }
18561
+ }
18562
+ function clearSavedLogsFilters(storageKey = DEFAULT_LOGS_FILTERS_STORAGE_KEY) {
18563
+ try {
18564
+ localStorage.removeItem(storageKey);
18565
+ } catch {
18566
+ }
18567
+ }
18568
+ function loadLogsFiltersFromStorage(storageKey = DEFAULT_LOGS_FILTERS_STORAGE_KEY) {
18569
+ try {
18570
+ const raw = localStorage.getItem(storageKey);
18571
+ if (!raw) return null;
18572
+ const parsed = new URLSearchParams(raw);
18573
+ return parsed.toString() ? parsed : null;
18574
+ } catch {
18575
+ return null;
18576
+ }
18577
+ }
18578
+ function hasAnyLogsFilterParams(params) {
18579
+ if (params.has(LOGS_DATE_PRESET_PARAM)) return true;
18580
+ if (params.has(LOGS_DATE_FROM_PARAM)) return true;
18581
+ if (params.has(LOGS_DATE_TO_PARAM)) return true;
18582
+ if (params.has(LOGS_ROOT_ENTITY_TYPE_PARAM)) return true;
18583
+ for (const fieldId of LOGS_PROPERTY_FILTER_FIELD_IDS) {
18584
+ if (params.has(LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId])) return true;
18585
+ }
18586
+ return false;
18587
+ }
18588
+ function createLogsPropertyFilterFields({
18589
+ availableTags,
18590
+ availableRootEntityNames,
18591
+ availableServiceNames,
18592
+ availableEnvironments,
18593
+ loading
18594
+ }) {
18595
+ const fields = [
18596
+ {
18597
+ id: "rootEntityType",
18598
+ label: "Primitive Type",
18599
+ kind: "pick-multi",
18600
+ searchable: false,
18601
+ options: LOGS_ROOT_ENTITY_TYPE_OPTIONS.map((o) => ({ label: o.label, value: o.entityType })),
18602
+ placeholder: "Choose entity type",
18603
+ emptyText: "No entity types."
18604
+ },
18605
+ {
18606
+ id: "entityName",
18607
+ label: "Primitive Name",
18608
+ kind: "pick-multi",
18609
+ options: availableRootEntityNames.map((name) => ({ label: name, value: name })),
18610
+ placeholder: "Choose entity names",
18611
+ emptyText: "No entity names found.",
18612
+ isLoading: loading?.entityNames
18613
+ },
18614
+ {
18615
+ id: "level",
18616
+ label: "Level",
18617
+ kind: "pick-multi",
18618
+ searchable: false,
18619
+ options: LOG_LEVEL_OPTIONS.map((o) => ({ label: o.label, value: o.value })),
18620
+ placeholder: "Choose level",
18621
+ emptyText: "No levels."
18622
+ },
18623
+ {
18624
+ id: "tags",
18625
+ label: "Tags",
18626
+ kind: "pick-multi",
18627
+ multi: true,
18628
+ options: availableTags.map((tag) => ({ label: tag, value: tag })),
18629
+ placeholder: "Choose tags",
18630
+ emptyText: "No tags found.",
18631
+ isLoading: loading?.tags
18632
+ },
18633
+ {
18634
+ id: "serviceName",
18635
+ label: "Service Name",
18636
+ kind: "pick-multi",
18637
+ options: availableServiceNames.map((name) => ({ label: name, value: name })),
18638
+ placeholder: "Choose service names",
18639
+ emptyText: "No service names found.",
18640
+ isLoading: loading?.serviceNames
18641
+ },
18642
+ {
18643
+ id: "environment",
18644
+ label: "Environment",
18645
+ kind: "pick-multi",
18646
+ options: availableEnvironments.map((env) => ({ label: env, value: env })),
18647
+ placeholder: "Choose environments",
18648
+ emptyText: "No environments found.",
18649
+ isLoading: loading?.environments
18650
+ },
18651
+ { id: "traceId", label: "Trace ID", kind: "text" },
18652
+ { id: "spanId", label: "Span ID", kind: "text" },
18653
+ { id: "runId", label: "Run ID", kind: "text" },
18654
+ { id: "threadId", label: "Thread ID", kind: "text" },
18655
+ { id: "sessionId", label: "Session ID", kind: "text" },
18656
+ { id: "requestId", label: "Request ID", kind: "text" },
18657
+ { id: "resourceId", label: "Resource ID", kind: "text" },
18658
+ { id: "userId", label: "User ID", kind: "text" },
18659
+ { id: "organizationId", label: "Organization ID", kind: "text" },
18660
+ { id: "experimentId", label: "Experiment ID", kind: "text" }
18661
+ ];
18662
+ const byLabel = (a, b) => a.label.localeCompare(b.label);
18663
+ const pickMulti = fields.filter((f) => f.kind === "pick-multi").sort(byLabel);
18664
+ const text = fields.filter((f) => f.kind === "text").sort(byLabel);
18665
+ return [...pickMulti, ...text];
18666
+ }
18667
+ function getLogsPropertyFilterTokens(searchParams) {
18668
+ const tokens = [];
18669
+ const paramToFieldId = /* @__PURE__ */ new Map([[LOGS_ROOT_ENTITY_TYPE_PARAM, "rootEntityType"]]);
18670
+ for (const fieldId of LOGS_PROPERTY_FILTER_FIELD_IDS) {
18671
+ paramToFieldId.set(LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId], fieldId);
18672
+ }
18673
+ const seen = /* @__PURE__ */ new Set();
18674
+ for (const [paramName] of searchParams.entries()) {
18675
+ const fieldId = paramToFieldId.get(paramName);
18676
+ if (!fieldId || seen.has(fieldId)) continue;
18677
+ seen.add(fieldId);
18678
+ if (LOGS_ARRAY_FIELD_IDS.has(fieldId)) {
18679
+ const raw = searchParams.getAll(paramName);
18680
+ if (raw.length === 0) continue;
18681
+ tokens.push({ fieldId, value: raw.filter(Boolean) });
18682
+ continue;
18683
+ }
18684
+ const value = searchParams.get(paramName);
18685
+ if (value !== null) tokens.push({ fieldId, value });
18686
+ }
18687
+ return tokens;
18688
+ }
18689
+ function getPreservedLogsFilterParams(searchParams) {
18690
+ const next = new URLSearchParams();
18691
+ const rootEntityType = searchParams.get(LOGS_ROOT_ENTITY_TYPE_PARAM);
18692
+ if (rootEntityType) next.set(LOGS_ROOT_ENTITY_TYPE_PARAM, rootEntityType);
18693
+ for (const fieldId of LOGS_PROPERTY_FILTER_FIELD_IDS) {
18694
+ const param = LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId];
18695
+ if (LOGS_ARRAY_FIELD_IDS.has(fieldId)) {
18696
+ for (const value2 of searchParams.getAll(param)) {
18697
+ next.append(param, value2);
18698
+ }
18699
+ continue;
18700
+ }
18701
+ const value = searchParams.get(param);
18702
+ if (value) next.set(param, value);
18703
+ }
18704
+ return next;
18705
+ }
18706
+ function applyLogsPropertyFilterTokens(params, tokens) {
18707
+ params.delete(LOGS_ROOT_ENTITY_TYPE_PARAM);
18708
+ for (const fieldId of LOGS_PROPERTY_FILTER_FIELD_IDS) {
18709
+ params.delete(LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId]);
18710
+ }
18711
+ for (const token of tokens) {
18712
+ if (token.fieldId === "rootEntityType" && typeof token.value === "string") {
18713
+ params.set(LOGS_ROOT_ENTITY_TYPE_PARAM, token.value);
18714
+ continue;
18715
+ }
18716
+ const param = LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[token.fieldId];
18717
+ if (!param) continue;
18718
+ if (LOGS_ARRAY_FIELD_IDS.has(token.fieldId) && Array.isArray(token.value)) {
18719
+ if (token.value.length === 0) {
18720
+ params.append(param, "");
18721
+ } else {
18722
+ for (const value of token.value) {
18723
+ params.append(param, value);
18724
+ }
18725
+ }
18726
+ continue;
18727
+ }
18728
+ if (typeof token.value === "string") {
18729
+ params.set(param, token.value.trim());
18730
+ }
18731
+ }
18732
+ }
18733
+ function buildLogsListFilters({
18734
+ rootEntityType,
18735
+ dateFrom,
18736
+ dateTo,
18737
+ tokens
18738
+ }) {
18739
+ const filters = {};
18740
+ if (rootEntityType) {
18741
+ filters.rootEntityType = rootEntityType;
18742
+ }
18743
+ if (dateFrom || dateTo) {
18744
+ filters.timestamp = {
18745
+ ...dateFrom ? { start: dateFrom } : {},
18746
+ ...dateTo ? { end: dateTo } : {}
18747
+ };
18748
+ }
18749
+ for (const token of tokens) {
18750
+ if (token.fieldId === "tags") {
18751
+ if (Array.isArray(token.value) && token.value.length > 0) {
18752
+ filters.tags = token.value;
18753
+ } else if (typeof token.value === "string" && token.value.trim()) {
18754
+ filters.tags = [token.value.trim()];
18755
+ }
18756
+ continue;
18757
+ }
18758
+ if (token.fieldId === "level") {
18759
+ if (typeof token.value === "string" && token.value.trim() && token.value !== "Any") {
18760
+ filters.level = token.value;
18761
+ }
18762
+ continue;
18763
+ }
18764
+ if (typeof token.value !== "string") continue;
18765
+ if (!token.value.trim()) continue;
18766
+ if (token.value === "Any") continue;
18767
+ switch (token.fieldId) {
18768
+ case "entityName":
18769
+ filters.rootEntityName = token.value;
18770
+ break;
18771
+ case "traceId":
18772
+ filters.traceId = token.value;
18773
+ break;
18774
+ case "spanId":
18775
+ filters.spanId = token.value;
18776
+ break;
18777
+ case "runId":
18778
+ filters.runId = token.value;
18779
+ break;
18780
+ case "threadId":
18781
+ filters.threadId = token.value;
18782
+ break;
18783
+ case "sessionId":
18784
+ filters.sessionId = token.value;
18785
+ break;
18786
+ case "requestId":
18787
+ filters.requestId = token.value;
18788
+ break;
18789
+ case "resourceId":
18790
+ filters.resourceId = token.value;
18791
+ break;
18792
+ case "userId":
18793
+ filters.userId = token.value;
18794
+ break;
18795
+ case "organizationId":
18796
+ filters.organizationId = token.value;
18797
+ break;
18798
+ case "serviceName":
18799
+ filters.serviceName = token.value;
18800
+ break;
18801
+ case "environment":
18802
+ filters.environment = token.value;
18803
+ break;
18804
+ case "experimentId":
18805
+ filters.experimentId = token.value;
18806
+ break;
18807
+ }
18808
+ }
18809
+ return filters;
18810
+ }
18811
+ function neutralizeLogsFilterTokens(filterFields, filterTokens) {
18812
+ return filterTokens.map((token) => {
18813
+ const field = filterFields.find((f) => f.id === token.fieldId);
18814
+ if (!field) return token;
18815
+ if (field.kind === "text") return { fieldId: token.fieldId, value: "" };
18816
+ if (field.kind === "pick-multi") {
18817
+ return field.multi ? { fieldId: token.fieldId, value: [] } : { fieldId: token.fieldId, value: "Any" };
18818
+ }
18819
+ return token;
18820
+ });
18821
+ }
18822
+
18823
+ const LOG_PARAM = "logId";
18824
+ const TRACE_PARAM = "traceId";
18825
+ const SPAN_PARAM = "spanId";
18826
+ const DAY_MS = 24 * 60 * 60 * 1e3;
18827
+ const PRESET_MS = {
18828
+ "last-24h": DAY_MS,
18829
+ "last-3d": 3 * DAY_MS,
18830
+ "last-7d": 7 * DAY_MS,
18831
+ "last-14d": 14 * DAY_MS,
18832
+ "last-30d": 30 * DAY_MS
18833
+ };
18834
+ function clearSelectionParams(params) {
18835
+ params.delete(LOG_PARAM);
18836
+ params.delete(TRACE_PARAM);
18837
+ params.delete(SPAN_PARAM);
18838
+ }
18839
+ function useLogsUrlState(searchParams, setSearchParams, options) {
18840
+ const { onRemoveAll } = options ?? {};
18841
+ const datePreset = React.useMemo(() => {
18842
+ const value = searchParams.get(LOGS_DATE_PRESET_PARAM);
18843
+ return value && LOGS_DATE_PRESET_VALUES.has(value) ? value : "last-24h";
18844
+ }, [searchParams]);
18845
+ const dateFromParamRaw = searchParams.get(LOGS_DATE_FROM_PARAM);
18846
+ const dateToParamRaw = searchParams.get(LOGS_DATE_TO_PARAM);
18847
+ const selectedDateFrom = React.useMemo(() => {
18848
+ if (datePreset === "custom") {
18849
+ if (!dateFromParamRaw) return void 0;
18850
+ const parsed = new Date(dateFromParamRaw);
18851
+ return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
18852
+ }
18853
+ if (datePreset === "all") return void 0;
18854
+ const ms = PRESET_MS[datePreset];
18855
+ return ms ? new Date(Date.now() - ms) : void 0;
18856
+ }, [datePreset, dateFromParamRaw]);
18857
+ const selectedDateTo = React.useMemo(() => {
18858
+ if (datePreset !== "custom" || !dateToParamRaw) return void 0;
18859
+ const parsed = new Date(dateToParamRaw);
18860
+ return Number.isNaN(parsed.getTime()) ? void 0 : parsed;
18861
+ }, [datePreset, dateToParamRaw]);
18862
+ const datePresetRef = React.useRef(datePreset);
18863
+ datePresetRef.current = datePreset;
18864
+ const featuredLogId = searchParams.get(LOG_PARAM);
18865
+ const featuredTraceId = searchParams.get(TRACE_PARAM);
18866
+ const featuredSpanId = searchParams.get(SPAN_PARAM);
18867
+ const selectedEntityOption = React.useMemo(
18868
+ () => LOGS_ROOT_ENTITY_TYPE_OPTIONS.find((option) => option.entityType === searchParams.get(LOGS_ROOT_ENTITY_TYPE_PARAM)),
18869
+ [searchParams]
18870
+ );
18871
+ const filterTokens = React.useMemo(() => getLogsPropertyFilterTokens(searchParams), [searchParams]);
18872
+ const handleFeaturedChange = React.useCallback(
18873
+ (ids) => {
18874
+ setSearchParams(
18875
+ (prev) => {
18876
+ const next = new URLSearchParams(prev);
18877
+ for (const [field, value] of Object.entries(ids)) {
18878
+ const param = field === "logId" ? LOG_PARAM : field === "traceId" ? TRACE_PARAM : SPAN_PARAM;
18879
+ if (value) {
18880
+ next.set(param, value);
18881
+ } else {
18882
+ next.delete(param);
18883
+ }
18884
+ }
18885
+ return next;
18886
+ },
18887
+ { replace: true }
18888
+ );
18889
+ },
18890
+ [setSearchParams]
18891
+ );
18892
+ const applyFilterTokens = React.useCallback(
18893
+ (tokens) => {
18894
+ setSearchParams(
18895
+ (prev) => {
18896
+ const next = new URLSearchParams(prev);
18897
+ applyLogsPropertyFilterTokens(next, tokens);
18898
+ clearSelectionParams(next);
18899
+ return next;
18900
+ },
18901
+ { replace: true }
18902
+ );
18903
+ },
18904
+ [setSearchParams]
18905
+ );
18906
+ const handleFilterTokensChange = applyFilterTokens;
18907
+ const handleDateChange = React.useCallback(
18908
+ (value, type) => {
18909
+ if (datePresetRef.current !== "custom") return;
18910
+ const param = type === "from" ? LOGS_DATE_FROM_PARAM : LOGS_DATE_TO_PARAM;
18911
+ setSearchParams(
18912
+ (prev) => {
18913
+ const next = new URLSearchParams(prev);
18914
+ if (value) {
18915
+ next.set(param, value.toISOString());
18916
+ } else {
18917
+ next.delete(param);
18918
+ }
18919
+ clearSelectionParams(next);
18920
+ return next;
18921
+ },
18922
+ { replace: true }
18923
+ );
18924
+ },
18925
+ [setSearchParams]
18926
+ );
18927
+ const handleDatePresetChange = React.useCallback(
18928
+ (preset) => {
18929
+ datePresetRef.current = preset;
18930
+ setSearchParams(
18931
+ (prev) => {
18932
+ const next = new URLSearchParams(prev);
18933
+ if (preset === "last-24h") {
18934
+ next.delete(LOGS_DATE_PRESET_PARAM);
18935
+ next.delete(LOGS_DATE_FROM_PARAM);
18936
+ next.delete(LOGS_DATE_TO_PARAM);
18937
+ } else if (preset === "custom") {
18938
+ next.set(LOGS_DATE_PRESET_PARAM, "custom");
18939
+ } else {
18940
+ next.set(LOGS_DATE_PRESET_PARAM, preset);
18941
+ next.delete(LOGS_DATE_FROM_PARAM);
18942
+ next.delete(LOGS_DATE_TO_PARAM);
18943
+ }
18944
+ clearSelectionParams(next);
18945
+ return next;
18946
+ },
18947
+ { replace: true }
18948
+ );
18949
+ },
18950
+ [setSearchParams]
18951
+ );
18952
+ const handleRemoveAll = React.useCallback(() => {
18953
+ setSearchParams(
18954
+ (prev) => {
18955
+ const next = new URLSearchParams(prev);
18956
+ next.delete(LOGS_ROOT_ENTITY_TYPE_PARAM);
18957
+ for (const fieldId of LOGS_PROPERTY_FILTER_FIELD_IDS) {
18958
+ next.delete(LOGS_PROPERTY_FILTER_PARAM_BY_FIELD[fieldId]);
18959
+ }
18960
+ next.delete(LOGS_DATE_PRESET_PARAM);
18961
+ next.delete(LOGS_DATE_FROM_PARAM);
18962
+ next.delete(LOGS_DATE_TO_PARAM);
18963
+ clearSelectionParams(next);
18964
+ return next;
18965
+ },
18966
+ { replace: true }
18967
+ );
18968
+ onRemoveAll?.();
18969
+ }, [setSearchParams, onRemoveAll]);
18970
+ return React.useMemo(
18971
+ () => ({
18972
+ searchParams,
18973
+ setSearchParams,
18974
+ datePreset,
18975
+ selectedDateFrom,
18976
+ selectedDateTo,
18977
+ datePresetRef,
18978
+ featuredLogId,
18979
+ featuredTraceId,
18980
+ featuredSpanId,
18981
+ selectedEntityOption,
18982
+ filterTokens,
18983
+ handleFeaturedChange,
18984
+ handleFilterTokensChange,
18985
+ handleDateChange,
18986
+ handleDatePresetChange,
18987
+ handleRemoveAll,
18988
+ applyFilterTokens
18989
+ }),
18990
+ [
18991
+ searchParams,
18992
+ setSearchParams,
18993
+ datePreset,
18994
+ selectedDateFrom,
18995
+ selectedDateTo,
18996
+ datePresetRef,
18997
+ featuredLogId,
18998
+ featuredTraceId,
18999
+ featuredSpanId,
19000
+ selectedEntityOption,
19001
+ filterTokens,
19002
+ handleFeaturedChange,
19003
+ handleFilterTokensChange,
19004
+ handleDateChange,
19005
+ handleDatePresetChange,
19006
+ handleRemoveAll,
19007
+ applyFilterTokens
19008
+ ]
19009
+ );
19010
+ }
19011
+
19012
+ const DEFAULT_SAVED_MESSAGE = "Filters setting for Logs saved";
19013
+ const DEFAULT_CLEARED_MESSAGE = "Filters setting for Logs cleared up";
19014
+ function useLogsFilterPersistence(searchParams, setSearchParams, options) {
19015
+ const { storageKey, messages, skipHydration } = options ?? {};
19016
+ const [hasSavedFilters, setHasSavedFilters] = React.useState(() => loadLogsFiltersFromStorage(storageKey) !== null);
19017
+ const handleSave = React.useCallback(() => {
19018
+ saveLogsFiltersToStorage(searchParams, storageKey);
19019
+ setHasSavedFilters(true);
19020
+ const text = messages?.saved ?? DEFAULT_SAVED_MESSAGE;
19021
+ if (text !== false) toast.success(text);
19022
+ }, [searchParams, storageKey, messages?.saved]);
19023
+ const handleRemoveSaved = React.useCallback(() => {
19024
+ clearSavedLogsFilters(storageKey);
19025
+ setHasSavedFilters(false);
19026
+ const text = messages?.cleared ?? DEFAULT_CLEARED_MESSAGE;
19027
+ if (text !== false) toast.success(text);
19028
+ }, [storageKey, messages?.cleared]);
19029
+ const hydratedRef = React.useRef(false);
19030
+ React.useEffect(() => {
19031
+ if (skipHydration) return;
19032
+ if (hydratedRef.current) return;
19033
+ hydratedRef.current = true;
19034
+ if (hasAnyLogsFilterParams(searchParams)) return;
19035
+ const saved = loadLogsFiltersFromStorage(storageKey);
19036
+ if (!saved) return;
19037
+ setSearchParams(
19038
+ (prev) => {
19039
+ const next = new URLSearchParams(prev);
19040
+ for (const [key, value] of saved) {
19041
+ next.append(key, value);
19042
+ }
19043
+ return next;
19044
+ },
19045
+ { replace: true }
19046
+ );
19047
+ }, []);
19048
+ return { hasSavedFilters, handleSave, handleRemoveSaved };
19049
+ }
19050
+
19051
+ function hashCode(str) {
19052
+ let hash = 0;
19053
+ for (let i = 0; i < str.length; i++) {
19054
+ hash = (hash << 5) - hash + str.charCodeAt(i) | 0;
19055
+ }
19056
+ return (hash >>> 0).toString(36);
19057
+ }
19058
+ function buildLogIds(logs) {
19059
+ const ids = /* @__PURE__ */ new Map();
19060
+ for (const log of logs) {
19061
+ if (log.logId) {
19062
+ ids.set(log, log.logId);
19063
+ continue;
19064
+ }
19065
+ const ts = log.timestamp instanceof Date ? log.timestamp.toISOString() : log.timestamp;
19066
+ ids.set(log, hashCode(`${ts}${log.message ?? ""}${log.data ? JSON.stringify(log.data) : ""}`));
19067
+ }
19068
+ return ids;
19069
+ }
19070
+ function useLogsListNavigation(logs, featuredLogId, onFeaturedChange, featuredTraceId) {
19071
+ const logIdMap = React.useMemo(() => buildLogIds(logs), [logs]);
19072
+ const idToLog = React.useMemo(() => {
19073
+ const m = /* @__PURE__ */ new Map();
19074
+ for (let i = 0; i < logs.length; i++) {
19075
+ const id = logIdMap.get(logs[i]);
19076
+ if (id) m.set(id, { log: logs[i], idx: i });
19077
+ }
19078
+ return m;
19079
+ }, [logs, logIdMap]);
19080
+ const entry = featuredLogId ? idToLog.get(featuredLogId) : void 0;
19081
+ const featuredLogIdx = entry?.idx ?? -1;
19082
+ const featuredLog = featuredLogIdx >= 0 ? logs[featuredLogIdx] : null;
19083
+ const getLogId = React.useCallback((log) => logIdMap.get(log), [logIdMap]);
19084
+ const handleLogClick = React.useCallback(
19085
+ (log) => {
19086
+ const id = logIdMap.get(log);
19087
+ if (!id) return;
19088
+ if (featuredLogId === id) {
19089
+ onFeaturedChange({ logId: null });
19090
+ return;
19091
+ }
19092
+ if (featuredTraceId) {
19093
+ onFeaturedChange({ logId: id, traceId: log.traceId ?? null, spanId: null });
19094
+ } else {
19095
+ onFeaturedChange({ logId: id });
19096
+ }
19097
+ },
19098
+ [logIdMap, featuredLogId, featuredTraceId, onFeaturedChange]
19099
+ );
19100
+ const handlePreviousLog = featuredLogIdx > 0 ? () => {
19101
+ const prevLog = logs[featuredLogIdx - 1];
19102
+ const id = logIdMap.get(prevLog);
19103
+ if (featuredTraceId) {
19104
+ onFeaturedChange({ logId: id, traceId: prevLog.traceId ?? null, spanId: null });
19105
+ } else {
19106
+ onFeaturedChange({ logId: id });
19107
+ }
19108
+ } : void 0;
19109
+ const handleNextLog = featuredLogIdx >= 0 && featuredLogIdx < logs.length - 1 ? () => {
19110
+ const nextLog = logs[featuredLogIdx + 1];
19111
+ const id = logIdMap.get(nextLog);
19112
+ if (featuredTraceId) {
19113
+ onFeaturedChange({ logId: id, traceId: nextLog.traceId ?? null, spanId: null });
19114
+ } else {
19115
+ onFeaturedChange({ logId: id });
19116
+ }
19117
+ } : void 0;
19118
+ return {
19119
+ logIdMap,
19120
+ getLogId,
19121
+ featuredLog,
19122
+ handleLogClick,
19123
+ handlePreviousLog,
19124
+ handleNextLog
19125
+ };
19126
+ }
19127
+
15007
19128
  exports.Animations = tokens.Animations;
15008
19129
  exports.BorderColors = tokens.BorderColors;
15009
19130
  exports.BorderRadius = tokens.BorderRadius;
@@ -15034,12 +19155,15 @@ exports.ApiIcon = ApiIcon;
15034
19155
  exports.Avatar = Avatar;
15035
19156
  exports.AzureIcon = AzureIcon;
15036
19157
  exports.Badge = Badge;
19158
+ exports.BarListContent = BarListContent;
15037
19159
  exports.BranchIcon = BranchIcon;
15038
19160
  exports.BrandLoader = BrandLoader;
15039
19161
  exports.Breadcrumb = Breadcrumb;
15040
19162
  exports.Button = Button;
15041
19163
  exports.ButtonWithTooltip = ButtonWithTooltip;
15042
19164
  exports.ButtonsGroup = ButtonsGroup;
19165
+ exports.CHART_COLORS = CHART_COLORS;
19166
+ exports.CONTEXT_FIELD_IDS = CONTEXT_FIELD_IDS;
15043
19167
  exports.Card = Card;
15044
19168
  exports.CardContent = CardContent;
15045
19169
  exports.CardDescription = CardDescription;
@@ -15078,6 +19202,9 @@ exports.ContentBlocks = ContentBlocks;
15078
19202
  exports.CopyButton = CopyButton;
15079
19203
  exports.CrossIcon = CrossIcon;
15080
19204
  exports.Crumb = Crumb;
19205
+ exports.DATE_PRESETS = DATE_PRESETS;
19206
+ exports.DEFAULT_LOGS_FILTERS_STORAGE_KEY = DEFAULT_LOGS_FILTERS_STORAGE_KEY;
19207
+ exports.DEFAULT_TRACE_FILTERS_STORAGE_KEY = DEFAULT_TRACE_FILTERS_STORAGE_KEY;
15081
19208
  exports.DashboardCard = DashboardCard;
15082
19209
  exports.DataCodeSection = DataCodeSection;
15083
19210
  exports.DataDetailsPanel = DataDetailsPanel;
@@ -15086,6 +19213,7 @@ exports.DataList = DataList;
15086
19213
  exports.DataListSkeleton = DataListSkeleton;
15087
19214
  exports.DataPanel = DataPanel;
15088
19215
  exports.DatePicker = DatePicker;
19216
+ exports.DateRangeSelector = DateRangeSelector;
15089
19217
  exports.DateTimeCell = DateTimeCell;
15090
19218
  exports.DateTimePicker = DateTimePicker;
15091
19219
  exports.DateTimePickerContent = DateTimePickerContent;
@@ -15160,14 +19288,32 @@ exports.JSONSchemaForm = JSONSchemaForm;
15160
19288
  exports.JudgeIcon = JudgeIcon;
15161
19289
  exports.Kbd = Kbd;
15162
19290
  exports.KeyValueList = KeyValueList;
19291
+ exports.KpiCardView = KpiCardView;
19292
+ exports.LOGS_DATE_FROM_PARAM = LOGS_DATE_FROM_PARAM;
19293
+ exports.LOGS_DATE_PRESET_PARAM = LOGS_DATE_PRESET_PARAM;
19294
+ exports.LOGS_DATE_PRESET_VALUES = LOGS_DATE_PRESET_VALUES;
19295
+ exports.LOGS_DATE_TO_PARAM = LOGS_DATE_TO_PARAM;
19296
+ exports.LOGS_PROPERTY_FILTER_FIELD_IDS = LOGS_PROPERTY_FILTER_FIELD_IDS;
19297
+ exports.LOGS_PROPERTY_FILTER_PARAM_BY_FIELD = LOGS_PROPERTY_FILTER_PARAM_BY_FIELD;
19298
+ exports.LOGS_ROOT_ENTITY_TYPES = LOGS_ROOT_ENTITY_TYPES;
19299
+ exports.LOGS_ROOT_ENTITY_TYPE_OPTIONS = LOGS_ROOT_ENTITY_TYPE_OPTIONS;
19300
+ exports.LOGS_ROOT_ENTITY_TYPE_PARAM = LOGS_ROOT_ENTITY_TYPE_PARAM;
19301
+ exports.LOG_LEVEL_OPTIONS = LOG_LEVEL_OPTIONS;
19302
+ exports.LOG_LEVEL_VALUES = LOG_LEVEL_VALUES;
15163
19303
  exports.Label = Label;
19304
+ exports.LatencyCardView = LatencyCardView;
15164
19305
  exports.LatencyIcon = LatencyIcon;
15165
19306
  exports.ListSearch = ListSearch;
19307
+ exports.LogDetailsView = LogDetailsView;
15166
19308
  exports.Logo = Logo;
15167
19309
  exports.LogoWithoutText = LogoWithoutText;
15168
19310
  exports.LogsDataList = LogsDataList;
15169
19311
  exports.LogsDataListSkeleton = DataListSkeleton;
19312
+ exports.LogsErrorContent = LogsErrorContent;
15170
19313
  exports.LogsIcon = LogsIcon;
19314
+ exports.LogsLayout = LogsLayout;
19315
+ exports.LogsListView = LogsListView;
19316
+ exports.LogsToolbar = LogsToolbar;
15171
19317
  exports.MainContentContent = MainContentContent;
15172
19318
  exports.MainContentLayout = MainContentLayout;
15173
19319
  exports.MainHeader = MainHeader;
@@ -15185,12 +19331,15 @@ exports.MetricsFlexGrid = MetricsFlexGrid;
15185
19331
  exports.MetricsKpiCard = MetricsKpiCard;
15186
19332
  exports.MetricsLineChart = MetricsLineChart;
15187
19333
  exports.MetricsLineChartTooltip = MetricsLineChartTooltip;
19334
+ exports.MetricsProvider = MetricsProvider;
15188
19335
  exports.MistralIcon = MistralIcon;
19336
+ exports.ModelUsageCostCardView = ModelUsageCostCardView;
15189
19337
  exports.MultiColumn = MultiColumn;
15190
19338
  exports.MultiCombobox = MultiCombobox;
15191
19339
  exports.NestedFields = NestedFields;
15192
19340
  exports.NetlifyIcon = NetlifyIcon;
15193
19341
  exports.NoDataPageLayout = NoDataPageLayout;
19342
+ exports.NoLogsInfo = NoLogsInfo;
15194
19343
  exports.Notice = Notice;
15195
19344
  exports.Notification = Notification;
15196
19345
  exports.OPERATORS = OPERATORS;
@@ -15214,6 +19363,8 @@ exports.PromptIcon = PromptIcon;
15214
19363
  exports.PropertyFilterActions = PropertyFilterActions;
15215
19364
  exports.PropertyFilterApplied = PropertyFilterApplied;
15216
19365
  exports.PropertyFilterCreator = PropertyFilterCreator;
19366
+ exports.ROOT_ENTITY_TYPES = ROOT_ENTITY_TYPES;
19367
+ exports.ROOT_ENTITY_TYPE_OPTIONS = ROOT_ENTITY_TYPE_OPTIONS;
15217
19368
  exports.RadioGroup = RadioGroup;
15218
19369
  exports.RadioGroupItem = RadioGroupItem;
15219
19370
  exports.RepoIcon = RepoIcon;
@@ -15224,6 +19375,7 @@ exports.RuleFieldSelect = RuleFieldSelect;
15224
19375
  exports.RuleOperatorSelect = RuleOperatorSelect;
15225
19376
  exports.RuleRow = RuleRow;
15226
19377
  exports.RuleValueInput = RuleValueInput;
19378
+ exports.ScoresCardView = ScoresCardView;
15227
19379
  exports.ScoresDataList = ScoresDataList;
15228
19380
  exports.ScrollArea = ScrollArea;
15229
19381
  exports.ScrollBar = ScrollBar;
@@ -15250,10 +19402,25 @@ exports.Skeleton = Skeleton;
15250
19402
  exports.SkillIcon = SkillIcon;
15251
19403
  exports.SlashIcon = SlashIcon;
15252
19404
  exports.Slider = Slider;
19405
+ exports.SpanDataPanelView = SpanDataPanelView;
19406
+ exports.SpanDetailsView = SpanDetailsView;
19407
+ exports.SpanTokenUsage = SpanTokenUsage;
15253
19408
  exports.Spinner = Spinner;
19409
+ exports.StackedRunsBars = StackedRunsBars;
15254
19410
  exports.StatusBadge = StatusBadge;
15255
19411
  exports.SubSectionRoot = SubSectionRoot;
15256
19412
  exports.Switch = Switch;
19413
+ exports.TRACE_DATE_FROM_PARAM = TRACE_DATE_FROM_PARAM;
19414
+ exports.TRACE_DATE_PRESET_PARAM = TRACE_DATE_PRESET_PARAM;
19415
+ exports.TRACE_DATE_PRESET_VALUES = TRACE_DATE_PRESET_VALUES;
19416
+ exports.TRACE_DATE_TO_PARAM = TRACE_DATE_TO_PARAM;
19417
+ exports.TRACE_PROPERTY_FILTER_FIELD_IDS = TRACE_PROPERTY_FILTER_FIELD_IDS;
19418
+ exports.TRACE_PROPERTY_FILTER_PARAM_BY_FIELD = TRACE_PROPERTY_FILTER_PARAM_BY_FIELD;
19419
+ exports.TRACE_ROOT_ENTITY_TYPE_PARAM = TRACE_ROOT_ENTITY_TYPE_PARAM;
19420
+ exports.TRACE_STATUS_OPTIONS = TRACE_STATUS_OPTIONS;
19421
+ exports.TRACE_STATUS_PARAM = TRACE_STATUS_PARAM;
19422
+ exports.TRACE_STATUS_VALUES = TRACE_STATUS_VALUES;
19423
+ exports.TRACE_SYNTHETIC_FILTER_FIELD_IDS = TRACE_SYNTHETIC_FILTER_FIELD_IDS;
15257
19424
  exports.Tab = Tab;
15258
19425
  exports.TabContent = TabContent;
15259
19426
  exports.TabList = TabList;
@@ -15271,14 +19438,29 @@ exports.ThreadLink = ThreadLink;
15271
19438
  exports.ThreadList = ThreadList;
15272
19439
  exports.Threads = Threads;
15273
19440
  exports.TimePicker = TimePicker;
19441
+ exports.TimelineExpandCol = TimelineExpandCol;
19442
+ exports.TimelineNameCol = TimelineNameCol;
19443
+ exports.TimelineStructureSign = TimelineStructureSign;
19444
+ exports.TimelineTimingCol = TimelineTimingCol;
19445
+ exports.TokenUsageByAgentCardView = TokenUsageByAgentCardView;
15274
19446
  exports.ToolCoinIcon = ToolCoinIcon;
15275
19447
  exports.ToolsIcon = ToolsIcon;
15276
19448
  exports.Tooltip = Tooltip;
15277
19449
  exports.TooltipContent = TooltipContent;
15278
19450
  exports.TooltipProvider = TooltipProvider;
15279
19451
  exports.TooltipTrigger = TooltipTrigger;
19452
+ exports.TraceDataPanelView = TraceDataPanelView;
19453
+ exports.TraceDetailsView = TraceDetailsView;
15280
19454
  exports.TraceIcon = TraceIcon;
19455
+ exports.TraceKeysAndValues = TraceKeysAndValues;
19456
+ exports.TraceTimeline = TraceTimeline;
19457
+ exports.TraceTimelineSpan = TraceTimelineSpan;
15281
19458
  exports.TracesDataList = TracesDataList;
19459
+ exports.TracesErrorContent = TracesErrorContent;
19460
+ exports.TracesLayout = TracesLayout;
19461
+ exports.TracesListView = TracesListView;
19462
+ exports.TracesToolbar = TracesToolbar;
19463
+ exports.TracesVolumeCardView = TracesVolumeCardView;
15282
19464
  exports.Tree = Tree;
15283
19465
  exports.Truncate = Truncate;
15284
19466
  exports.TsIcon = TsIcon;
@@ -15289,13 +19471,21 @@ exports.VariablesIcon = VariablesIcon;
15289
19471
  exports.WorkflowCoinIcon = WorkflowCoinIcon;
15290
19472
  exports.WorkflowIcon = WorkflowIcon;
15291
19473
  exports.XGroqIcon = XGroqIcon;
19474
+ exports.applyLogsPropertyFilterTokens = applyLogsPropertyFilterTokens;
19475
+ exports.applyTracePropertyFilterTokens = applyTracePropertyFilterTokens;
19476
+ exports.buildLogsListFilters = buildLogsListFilters;
19477
+ exports.buildTraceListFilters = buildTraceListFilters;
15292
19478
  exports.buttonVariants = buttonVariants;
19479
+ exports.clearSavedLogsFilters = clearSavedLogsFilters;
19480
+ exports.clearSavedTraceFilters = clearSavedTraceFilters;
15293
19481
  exports.cn = cn;
15294
19482
  exports.comboboxStyles = comboboxStyles;
15295
19483
  exports.countLeafRules = countLeafRules;
15296
19484
  exports.createDefaultRule = createDefaultRule;
15297
19485
  exports.createDefaultRuleGroup = createDefaultRuleGroup;
15298
19486
  exports.createField = createField;
19487
+ exports.createLogsPropertyFilterFields = createLogsPropertyFilterFields;
19488
+ exports.createTracePropertyFilterFields = createTracePropertyFilterFields;
15299
19489
  exports.createVariableAutocomplete = createVariableAutocomplete;
15300
19490
  exports.fieldsToJSONSchema = fieldsToJSONSchema;
15301
19491
  exports.fileToBase64 = fileToBase64;
@@ -15306,21 +19496,36 @@ exports.formElementFocusWithin = formElementFocusWithin;
15306
19496
  exports.formElementRadius = formElementRadius;
15307
19497
  exports.formElementSizes = formElementSizes;
15308
19498
  exports.formElementTransition = formElementTransition;
19499
+ exports.formatCompact = formatCompact;
19500
+ exports.formatCost = formatCost;
19501
+ exports.formatHierarchicalSpans = formatHierarchicalSpans;
15309
19502
  exports.formatJSON = formatJSON;
15310
19503
  exports.generateDefaultValues = generateDefaultValues;
19504
+ exports.getAllSpanIds = getAllSpanIds;
15311
19505
  exports.getChildFieldOptions = getChildFieldOptions;
15312
19506
  exports.getColumnTemplate = getColumnTemplate;
15313
19507
  exports.getFieldOptionAtPath = getFieldOptionAtPath;
15314
19508
  exports.getFieldOptionsFromSchema = getFieldOptionsFromSchema;
15315
19509
  exports.getFileContentType = getFileContentType;
19510
+ exports.getInputPreview = getInputPreview;
15316
19511
  exports.getItemListColumnTemplate = getItemListColumnTemplate;
19512
+ exports.getLogsPropertyFilterTokens = getLogsPropertyFilterTokens;
15317
19513
  exports.getMainContentContentClassName = getMainContentContentClassName;
19514
+ exports.getPreservedLogsFilterParams = getPreservedLogsFilterParams;
19515
+ exports.getPreservedTraceFilterParams = getPreservedTraceFilterParams;
15318
19516
  exports.getShortId = getShortId$1;
19517
+ exports.getSpanDescendantIds = getSpanDescendantIds;
19518
+ exports.getSpanTypeUi = getSpanTypeUi;
15319
19519
  exports.getStatusIcon = getStatusIcon;
15320
19520
  exports.getToNextEntryFn = getToNextEntryFn;
15321
19521
  exports.getToNextItemFn = getToNextItemFn;
15322
19522
  exports.getToPreviousEntryFn = getToPreviousEntryFn;
15323
19523
  exports.getToPreviousItemFn = getToPreviousItemFn;
19524
+ exports.getTokenLimitMessage = getTokenLimitMessage;
19525
+ exports.getTracePropertyFilterTokens = getTracePropertyFilterTokens;
19526
+ exports.groupTracesByThread = groupTracesByThread;
19527
+ exports.hasAnyLogsFilterParams = hasAnyLogsFilterParams;
19528
+ exports.hasAnyTraceFilterParams = hasAnyTraceFilterParams;
15324
19529
  exports.highlight = highlight;
15325
19530
  exports.hoverEffects = hoverEffects;
15326
19531
  exports.inputVariants = inputVariants;
@@ -15330,32 +19535,68 @@ exports.isNonRetryableError = isNonRetryableError;
15330
19535
  exports.isObjectEmpty = isObjectEmpty;
15331
19536
  exports.isRule = isRule;
15332
19537
  exports.isRuleGroup = isRuleGroup;
19538
+ exports.isTokenLimitExceeded = isTokenLimitExceeded;
15333
19539
  exports.isValidJson = isValidJson;
19540
+ exports.isValidPreset = isValidPreset;
15334
19541
  exports.jsonSchemaToFields = jsonSchemaToFields;
19542
+ exports.loadLogsFiltersFromStorage = loadLogsFiltersFromStorage;
19543
+ exports.loadTraceFiltersFromStorage = loadTraceFiltersFromStorage;
15335
19544
  exports.lodashTitleCase = lodashTitleCase;
19545
+ exports.neutralizeFilterTokens = neutralizeFilterTokens;
19546
+ exports.neutralizeLogsFilterTokens = neutralizeLogsFilterTokens;
15336
19547
  exports.parseError = parseError;
15337
19548
  exports.parseFieldPath = parseFieldPath;
19549
+ exports.saveLogsFiltersToStorage = saveLogsFiltersToStorage;
19550
+ exports.saveTraceFiltersToStorage = saveTraceFiltersToStorage;
15338
19551
  exports.sharedFormElementDisabledStyle = sharedFormElementDisabledStyle;
15339
19552
  exports.sharedFormElementFocusStyle = sharedFormElementFocusStyle;
15340
19553
  exports.sharedFormElementStyle = sharedFormElementStyle;
15341
19554
  exports.shouldRetryQuery = shouldRetryQuery;
19555
+ exports.spanTypePrefixes = spanTypePrefixes;
15342
19556
  exports.stringToColor = stringToColor;
15343
19557
  exports.textareaVariants = textareaVariants;
15344
19558
  exports.toSigFigs = toSigFigs;
15345
19559
  exports.toast = toast;
15346
19560
  exports.transitions = transitions;
15347
19561
  exports.truncateString = truncateString;
19562
+ exports.useAgentRunsKpiMetrics = useAgentRunsKpiMetrics;
15348
19563
  exports.useAutoscroll = useAutoscroll;
19564
+ exports.useAvgScoreKpiMetrics = useAvgScoreKpiMetrics;
15349
19565
  exports.useCodemirrorTheme = useCodemirrorTheme$3;
15350
19566
  exports.useCopyToClipboard = useCopyToClipboard;
19567
+ exports.useEntityNames = useEntityNames;
19568
+ exports.useEnvironments = useEnvironments;
15351
19569
  exports.useInView = useInView;
15352
19570
  exports.useIsDarkMode = useIsDarkMode;
15353
19571
  exports.useJSONSchemaForm = useJSONSchemaForm;
15354
19572
  exports.useJSONSchemaFormField = useJSONSchemaFormField;
15355
19573
  exports.useJSONSchemaFormNestedContext = useJSONSchemaFormNestedContext;
19574
+ exports.useLatencyMetrics = useLatencyMetrics;
19575
+ exports.useLogs = useLogs;
19576
+ exports.useLogsFilterPersistence = useLogsFilterPersistence;
19577
+ exports.useLogsListNavigation = useLogsListNavigation;
19578
+ exports.useLogsUrlState = useLogsUrlState;
15356
19579
  exports.useMainSidebar = useMainSidebar;
15357
19580
  exports.useMaybeSidebar = useMaybeSidebar;
19581
+ exports.useMetrics = useMetrics;
19582
+ exports.useMetricsFilters = useMetricsFilters;
19583
+ exports.useModelCostKpiMetrics = useModelCostKpiMetrics;
19584
+ exports.useModelUsageCostMetrics = useModelUsageCostMetrics;
15358
19585
  exports.usePlaygroundStore = usePlaygroundStore;
19586
+ exports.useScoresMetrics = useScoresMetrics;
19587
+ exports.useServiceNames = useServiceNames;
19588
+ exports.useSpanDetail = useSpanDetail;
15359
19589
  exports.useTableKeyboardNavigation = useTableKeyboardNavigation;
19590
+ exports.useTags = useTags;
19591
+ exports.useTokenUsageByAgentMetrics = useTokenUsageByAgentMetrics;
19592
+ exports.useTotalTokensKpiMetrics = useTotalTokensKpiMetrics;
19593
+ exports.useTraceFilterPersistence = useTraceFilterPersistence;
19594
+ exports.useTraceLightSpans = useTraceLightSpans;
19595
+ exports.useTraceListNavigation = useTraceListNavigation;
19596
+ exports.useTraceSpanNavigation = useTraceSpanNavigation;
19597
+ exports.useTraceSpans = useTraceSpans;
19598
+ exports.useTraceUrlState = useTraceUrlState;
19599
+ exports.useTraceVolumeMetrics = useTraceVolumeMetrics;
19600
+ exports.useTraces = useTraces;
15360
19601
  exports.variableHighlight = variableHighlight;
15361
19602
  //# sourceMappingURL=index.cjs.js.map