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