@truefoundry/trueforge-ui 0.3.0-rc.0 → 0.3.0-rc.10

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 (115) hide show
  1. package/CHANGELOG.md +191 -0
  2. package/README.md +35 -12
  3. package/dist/AgentCodeSnippets-RJBB4DDE.js +89 -0
  4. package/dist/AgentCodeSnippets-RJBB4DDE.js.map +1 -0
  5. package/dist/AgentMetricChart-UPGSJ2WP.js +15 -0
  6. package/dist/AgentOverview-U5WIQXZN.js +169 -0
  7. package/dist/AgentOverview-U5WIQXZN.js.map +1 -0
  8. package/dist/AgentSessionEventTimeline-GRGIQTRE.js +88 -0
  9. package/dist/AgentSessionEventTimeline-GRGIQTRE.js.map +1 -0
  10. package/dist/AgentSessionEventTimelineChart-GNF4VOUT.js +591 -0
  11. package/dist/AgentSessionEventTimelineChart-GNF4VOUT.js.map +1 -0
  12. package/dist/AgentSessions-5OTF2BUW.js +323 -0
  13. package/dist/AgentSessions-5OTF2BUW.js.map +1 -0
  14. package/dist/{ConnectorSettings-FXQ5B7TN.js → ConnectorSettings-HDKGLDCY.js} +163 -125
  15. package/dist/ConnectorSettings-HDKGLDCY.js.map +1 -0
  16. package/dist/{DockLayout-LBNQJZNF.js → DockLayout-D2FPQCAL.js} +11 -10
  17. package/dist/{DockLayout-LBNQJZNF.js.map → DockLayout-D2FPQCAL.js.map} +1 -1
  18. package/dist/DrawerLayout-HUV7RAWL.js +186 -0
  19. package/dist/DrawerLayout-HUV7RAWL.js.map +1 -0
  20. package/dist/{ModelSettings-4L4LOQJA.js → ModelSettings-VNQ7HPKH.js} +23 -27
  21. package/dist/ModelSettings-VNQ7HPKH.js.map +1 -0
  22. package/dist/OpenUiFenceBlock-KPZFLUSC.js +9 -0
  23. package/dist/OpenUiFenceBlock-KPZFLUSC.js.map +1 -0
  24. package/dist/{SandboxSettings-Z4ZG6ZX4.js → SandboxSettings-ZLXGMFBF.js} +18 -20
  25. package/dist/SandboxSettings-ZLXGMFBF.js.map +1 -0
  26. package/dist/SchedulesPage-QKYI2Z3A.js +15 -0
  27. package/dist/SchedulesPage-QKYI2Z3A.js.map +1 -0
  28. package/dist/{SettingsBuilder-WF7ZWKQW.js → SettingsBuilder-RVVYXOJW.js} +27 -23
  29. package/dist/SettingsBuilder-RVVYXOJW.js.map +1 -0
  30. package/dist/ShellRouteSync-SJXFKUAJ.js +390 -0
  31. package/dist/ShellRouteSync-SJXFKUAJ.js.map +1 -0
  32. package/dist/SidebarLayout-KYA76FQ7.js +330 -0
  33. package/dist/SidebarLayout-KYA76FQ7.js.map +1 -0
  34. package/dist/{SkillSettings-3EPPC3IT.js → SkillSettings-7OHT7FPI.js} +25 -21
  35. package/dist/SkillSettings-7OHT7FPI.js.map +1 -0
  36. package/dist/{TrueForgeUIWithRouter-NZ4FGPE4.js → TrueForgeUIWithRouter-LKG4XLW6.js} +14 -10
  37. package/dist/{TrueForgeUIWithRouter-NZ4FGPE4.js.map → TrueForgeUIWithRouter-LKG4XLW6.js.map} +1 -1
  38. package/dist/{WidgetLayout-3QZ357FL.js → WidgetLayout-W2RGGOQ3.js} +17 -13
  39. package/dist/WidgetLayout-W2RGGOQ3.js.map +1 -0
  40. package/dist/chunk-2GIZY3JJ.js +1062 -0
  41. package/dist/chunk-2GIZY3JJ.js.map +1 -0
  42. package/dist/chunk-2QTH6JHX.js +217 -0
  43. package/dist/chunk-2QTH6JHX.js.map +1 -0
  44. package/dist/{chunk-FJ5RSSMA.js → chunk-3ZW74FHC.js} +118 -164
  45. package/dist/chunk-3ZW74FHC.js.map +1 -0
  46. package/dist/chunk-67ZO7Z2W.js +184 -0
  47. package/dist/chunk-67ZO7Z2W.js.map +1 -0
  48. package/dist/{chunk-CFLVPV5M.js → chunk-7AAO4UDQ.js} +8 -2
  49. package/dist/chunk-7AAO4UDQ.js.map +1 -0
  50. package/dist/{chunk-B52K63AW.js → chunk-CG75X77Q.js} +2 -2
  51. package/dist/chunk-DJUFS2BW.js +27 -0
  52. package/dist/chunk-DJUFS2BW.js.map +1 -0
  53. package/dist/chunk-DPPOEFBD.js +517 -0
  54. package/dist/chunk-DPPOEFBD.js.map +1 -0
  55. package/dist/chunk-EPAL2HD5.js +1629 -0
  56. package/dist/chunk-EPAL2HD5.js.map +1 -0
  57. package/dist/chunk-GG23N2GW.js +15018 -0
  58. package/dist/chunk-GG23N2GW.js.map +1 -0
  59. package/dist/chunk-JCL3Q7RW.js +587 -0
  60. package/dist/chunk-JCL3Q7RW.js.map +1 -0
  61. package/dist/chunk-JKEBMGLH.js +682 -0
  62. package/dist/chunk-JKEBMGLH.js.map +1 -0
  63. package/dist/chunk-KSGNKS2D.js +296 -0
  64. package/dist/chunk-KSGNKS2D.js.map +1 -0
  65. package/dist/{chunk-WREC7D54.js → chunk-PCI6VMB5.js} +268 -48
  66. package/dist/chunk-PCI6VMB5.js.map +1 -0
  67. package/dist/chunk-PQ7VWBQQ.js +121 -0
  68. package/dist/chunk-PQ7VWBQQ.js.map +1 -0
  69. package/dist/chunk-RDXBMTP5.js +32 -0
  70. package/dist/chunk-RDXBMTP5.js.map +1 -0
  71. package/dist/chunk-T6QQV5LK.js +238 -0
  72. package/dist/chunk-T6QQV5LK.js.map +1 -0
  73. package/dist/chunk-Y6S4OVVQ.js +16 -0
  74. package/dist/chunk-Y6S4OVVQ.js.map +1 -0
  75. package/dist/{createTrueFoundryServer-B72bU-J7.d.ts → createTrueFoundryServer-B_FYhSdn.d.ts} +18 -4
  76. package/dist/index.d.ts +1287 -46
  77. package/dist/index.js +266 -63
  78. package/dist/index.js.map +1 -1
  79. package/dist/plugins/trueforge-agent-server-adapter/index.d.ts +590 -11
  80. package/dist/plugins/trueforge-agent-server-adapter/index.js +607 -204
  81. package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -1
  82. package/dist/styles.css +1 -1
  83. package/package.json +10 -8
  84. package/dist/ConnectorSettings-FXQ5B7TN.js.map +0 -1
  85. package/dist/DrawerLayout-Q6UK4VMI.js +0 -159
  86. package/dist/DrawerLayout-Q6UK4VMI.js.map +0 -1
  87. package/dist/ModelSettings-4L4LOQJA.js.map +0 -1
  88. package/dist/OpenUiFenceBlock-6UIIAVBX.js +0 -9
  89. package/dist/SandboxSettings-Z4ZG6ZX4.js.map +0 -1
  90. package/dist/SettingsBuilder-WF7ZWKQW.js.map +0 -1
  91. package/dist/ShellRouteSync-T4WLY57Q.js +0 -172
  92. package/dist/ShellRouteSync-T4WLY57Q.js.map +0 -1
  93. package/dist/SidebarLayout-3WZ3CVON.js +0 -256
  94. package/dist/SidebarLayout-3WZ3CVON.js.map +0 -1
  95. package/dist/SkillSettings-3EPPC3IT.js.map +0 -1
  96. package/dist/WidgetLayout-3QZ357FL.js.map +0 -1
  97. package/dist/chunk-36KOSC2J.js +0 -567
  98. package/dist/chunk-36KOSC2J.js.map +0 -1
  99. package/dist/chunk-3S6KHO7H.js +0 -2121
  100. package/dist/chunk-3S6KHO7H.js.map +0 -1
  101. package/dist/chunk-7L63OK3O.js +0 -91
  102. package/dist/chunk-7L63OK3O.js.map +0 -1
  103. package/dist/chunk-CFLVPV5M.js.map +0 -1
  104. package/dist/chunk-FJ5RSSMA.js.map +0 -1
  105. package/dist/chunk-OSV3HI5M.js +0 -6891
  106. package/dist/chunk-OSV3HI5M.js.map +0 -1
  107. package/dist/chunk-WQULF5AT.js +0 -460
  108. package/dist/chunk-WQULF5AT.js.map +0 -1
  109. package/dist/chunk-WREC7D54.js.map +0 -1
  110. package/dist/chunk-YIWUG6MC.js +0 -101
  111. package/dist/chunk-YIWUG6MC.js.map +0 -1
  112. package/dist/chunk-ZXOADNF3.js +0 -75
  113. package/dist/chunk-ZXOADNF3.js.map +0 -1
  114. /package/dist/{OpenUiFenceBlock-6UIIAVBX.js.map → AgentMetricChart-UPGSJ2WP.js.map} +0 -0
  115. /package/dist/{chunk-B52K63AW.js.map → chunk-CG75X77Q.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/atoms/agent-details/AgentSessionEventTimelineChart.tsx","../src/atoms/agent-details/AgentSessionTimelineTooltip.tsx"],"sourcesContent":["'use client';\n\nimport {\n BarController,\n BarElement,\n Chart as ChartJS,\n LinearScale,\n PointElement,\n ScatterController,\n Tooltip,\n type ChartData,\n type ChartDataset,\n type ChartOptions,\n type Plugin,\n} from 'chart.js';\nimport { useCallback, useEffect, useMemo, useRef, useState, type ComponentType, type CSSProperties } from 'react';\nimport { Chart } from 'react-chartjs-2';\n\nimport { useThemeMode } from '../../theme/SlotsProvider.js';\nimport { roundDurationMsToSecond } from '../../utils/sessionDisplayFormat.js';\nimport {\n getSessionEventColor,\n getSessionEventHoverColor,\n getSessionEventLabel,\n MAIN_THREAD_ID,\n type SessionEventTimelineSegment,\n} from '../../utils/sessionEventTimeline.js';\nimport {\n buildTimelineAxisTicks,\n formatTimelineAxisDuration,\n getActiveTimelineMs,\n getSubAgentHoverGroups,\n getSubAgentLanes,\n getTimelineHoverTargetId,\n getTimelineLayout,\n getTimelineRange,\n groupCoincidentTimelineMarkers,\n groupOverlappingToolCalls,\n mergeOverlappingSubAgentSegments,\n TIMELINE_TYPE,\n type TimelineGap,\n type TimelineHoverTarget,\n type TimelineTurnBar,\n} from '../../utils/sessionEventTimelineChart.js';\nimport { LightTooltip } from '../primitives/Tooltip.js';\nimport {\n hasSessionEventTooltip,\n SessionEventTooltip,\n SessionMarkerGroupTooltip,\n SessionSubAgentGroupTooltip,\n SessionToolCallGroupTooltip,\n SessionTurnTooltip,\n} from './AgentSessionTimelineTooltip.js';\nimport type { AgentSessionEventTimelineChartProps } from './types.js';\n\nChartJS.register(BarController, BarElement, LinearScale, PointElement, ScatterController, Tooltip);\n\nconst MARKER_PX = 4;\nconst TURN_GAP_PX = 12;\nconst END_PAD_PX = 12;\nconst BAR_RADIUS_PX = 2;\nconst ROW_GAP_PX = 8;\nconst MARKER_EVENT_GAP_PX = 2;\nconst OVERHEAD_PX = 30;\n\ntype BarPoint = { x: [number, number]; y: number };\ntype MarkerPoint = { x: number; y: number };\ntype TimelineChartType = 'bar' | 'scatter';\n\nfunction rowCenters({ heights, gaps }: { heights: number[]; gaps: number[] }): { centers: number[]; band: number } {\n const centers: number[] = [];\n let offset = 0;\n heights.forEach((height, index) => {\n centers.push(offset + height / 2);\n offset += height + (gaps[index] ?? 0);\n });\n return { centers, band: offset };\n}\n\nfunction eventOrder(type: SessionEventTimelineSegment['type']): number {\n if (type === 'sub_agent') return 0;\n if (type === 'model') return 2;\n return 1;\n}\n\nfunction turnBarLabelPoint(element: object): { x: number; y: number } | null {\n if (!('x' in element) || !('y' in element) || !('base' in element)) return null;\n const { x, y, base } = element;\n if (typeof x !== 'number' || typeof y !== 'number' || typeof base !== 'number') return null;\n return { x: (x + base) / 2, y };\n}\n\nexport function AgentSessionEventTimelineChart({\n turns,\n segments,\n hiddenTypes,\n onSelectTurn,\n}: AgentSessionEventTimelineChartProps) {\n const mode = useThemeMode();\n const isDark = mode === 'dark';\n const axis = isDark ? '#8c8c92' : '#71717a';\n const grid = isDark ? '#27272a' : '#e4e4e7';\n const turnFill = isDark ? '#3f3f46' : '#E0ECFD';\n const turnHover = isDark ? '#52525b' : '#E0ECFD';\n const wrapperRef = useRef<HTMLDivElement>(null);\n const [widthPx, setWidthPx] = useState(0);\n const [overheadPx, setOverheadPx] = useState(OVERHEAD_PX);\n const [tooltipTarget, setTooltipTarget] = useState<TimelineHoverTarget | null>(null);\n const [tooltipAnchor, setTooltipAnchor] = useState<{ left: number; top: number } | null>(null);\n const tooltipIdRef = useRef('');\n const tooltipCursorXRef = useRef<number | null>(null);\n\n useEffect(() => {\n const wrapper = wrapperRef.current;\n if (wrapper == null) return undefined;\n const update = () => setWidthPx(wrapper.clientWidth);\n update();\n const observer = new ResizeObserver(update);\n observer.observe(wrapper);\n return () => observer.disconnect();\n }, []);\n\n const refreshTooltipAnchor = useCallback(() => {\n const wrapper = wrapperRef.current;\n const left = tooltipCursorXRef.current;\n if (wrapper == null || left == null) return;\n setTooltipAnchor({ left, top: wrapper.getBoundingClientRect().bottom });\n }, []);\n\n const clearTooltip = useCallback(() => {\n tooltipIdRef.current = '';\n tooltipCursorXRef.current = null;\n setTooltipTarget(null);\n setTooltipAnchor(null);\n }, []);\n\n useEffect(() => {\n if (tooltipTarget == null) return undefined;\n // Anchors use viewport coordinates, so remeasure the chart whenever any\n // scroll ancestor or the viewport moves it.\n refreshTooltipAnchor();\n window.addEventListener('scroll', refreshTooltipAnchor, true);\n window.addEventListener('resize', refreshTooltipAnchor);\n return () => {\n window.removeEventListener('scroll', refreshTooltipAnchor, true);\n window.removeEventListener('resize', refreshTooltipAnchor);\n };\n }, [refreshTooltipAnchor, tooltipTarget]);\n\n const segmentTotalMs = Math.max(0, ...segments.map(segment => segment.endMs));\n const activeTotalMs = Math.max(1, roundDurationMsToSecond(segmentTotalMs));\n const { turnStartsMs, turnOrdinals, turnRanges } = useMemo(() => getTimelineLayout(segments), [segments]);\n const activeTurnStartsMs = useMemo(\n () => turnStartsMs.filter((startMs, index) => index === 0 || startMs <= activeTotalMs),\n [activeTotalMs, turnStartsMs],\n );\n const gapCount = Math.max(0, activeTurnStartsMs.length - 1);\n const scaleWidthPx = Math.max(widthPx / 2, widthPx - TURN_GAP_PX * gapCount - END_PAD_PX);\n const msPerPx = activeTotalMs / Math.max(1, scaleWidthPx);\n const turnGapMs = TURN_GAP_PX * msPerPx;\n const totalMs = activeTotalMs + gapCount * turnGapMs;\n const timelineMaxMs = totalMs + END_PAD_PX * msPerPx;\n const timelineGaps = useMemo<TimelineGap[]>(\n () =>\n activeTurnStartsMs\n .slice(1)\n .map((startMs, index) => ({ startMs: startMs + index * turnGapMs, endMs: startMs + (index + 1) * turnGapMs })),\n [activeTurnStartsMs, turnGapMs],\n );\n\n const visibleSegments = useMemo(\n () =>\n segments.flatMap(segment => {\n if (hiddenTypes.has(segment.type)) return [];\n const shiftMs = (turnOrdinals.get(segment.turnIndex) ?? 0) * turnGapMs;\n return [{ ...segment, startMs: segment.startMs + shiftMs, endMs: segment.endMs + shiftMs }];\n }),\n [hiddenTypes, segments, turnGapMs, turnOrdinals],\n );\n const markerGroups = useMemo(() => groupCoincidentTimelineMarkers(visibleSegments), [visibleSegments]);\n const durationSegments = useMemo(() => visibleSegments.filter(segment => !segment.isMarker), [visibleSegments]);\n const turnBars = useMemo<TimelineTurnBar[]>(\n () =>\n turnRanges.length < 2\n ? []\n : turnRanges.map(range => ({\n ...range,\n id: `turn-${range.turnIndex}`,\n durationMs: range.endMs - range.startMs,\n startMs: range.startMs + range.ordinal * turnGapMs,\n endMs: range.endMs + range.ordinal * turnGapMs + MARKER_PX * msPerPx,\n })),\n [msPerPx, turnGapMs, turnRanges],\n );\n const subAgentSegments = useMemo(\n () => durationSegments.filter(segment => segment.type === 'sub_agent'),\n [durationSegments],\n );\n const mainSubAgents = useMemo(() => mergeOverlappingSubAgentSegments(subAgentSegments), [subAgentSegments]);\n const subAgentGroups = useMemo(\n () => getSubAgentHoverGroups({ bars: mainSubAgents, subAgentSegments }),\n [mainSubAgents, subAgentSegments],\n );\n const subAgentLanes = useMemo(\n () => getSubAgentLanes({ subAgentSegments, threadSegments: durationSegments, minWidthMs: MARKER_PX * msPerPx }),\n [durationSegments, msPerPx, subAgentSegments],\n );\n const mainCandidates = useMemo(() => {\n return [...durationSegments.filter(segment => segment.threadId === MAIN_THREAD_ID), ...mainSubAgents].sort(\n (left, right) => left.startMs - right.startMs || left.endMs - right.endMs,\n );\n }, [durationSegments, mainSubAgents]);\n const toolCallGroups = useMemo(\n () =>\n groupOverlappingToolCalls(mainCandidates.filter(segment => segment.type === 'tool_call')).filter(\n group => group.segments.length > 1,\n ),\n [mainCandidates],\n );\n const groupedIds = useMemo(\n () => new Set(toolCallGroups.flatMap(group => group.segments.map(segment => segment.id))),\n [toolCallGroups],\n );\n const mainEventSegments = useMemo(\n () => mainCandidates.filter(segment => !groupedIds.has(segment.id)),\n [groupedIds, mainCandidates],\n );\n const laneCount = subAgentLanes.reduce((count, lane) => Math.max(count, lane.lane + 1), 0);\n const hasTurnRow = turnBars.length > 0;\n const markerRow = hasTurnRow ? 1 : 0;\n const eventRow = markerRow + 1;\n const { centers, band } = useMemo(() => {\n const heights = [...(hasTurnRow ? [16] : []), 10, 28, ...Array.from({ length: laneCount }, () => 12)];\n const gaps = heights.map((_, index) => {\n if (index === heights.length - 1) return 0;\n return index === markerRow ? MARKER_EVENT_GAP_PX : ROW_GAP_PX;\n });\n return rowCenters({ heights, gaps });\n }, [hasTurnRow, laneCount, markerRow]);\n\n const chartTargets = useMemo<Array<TimelineHoverTarget | null>>(\n () => [\n ...turnBars.map((bar): TimelineHoverTarget => ({ type: TIMELINE_TYPE.turn, bar })),\n ...markerGroups.map((group): TimelineHoverTarget => ({ type: TIMELINE_TYPE.markerGroup, group })),\n ...subAgentLanes.flatMap(lane =>\n lane.segments.map((segment): TimelineHoverTarget => ({ type: TIMELINE_TYPE.event, segment })),\n ),\n ...mainEventSegments.map((segment): TimelineHoverTarget | null => {\n if (segment.type !== 'sub_agent') return { type: TIMELINE_TYPE.event, segment };\n const group = subAgentGroups.find(candidate => candidate.barId === segment.id);\n return group == null ? { type: TIMELINE_TYPE.event, segment } : { type: TIMELINE_TYPE.subAgentGroup, group };\n }),\n ...toolCallGroups.map((group): TimelineHoverTarget => ({ type: TIMELINE_TYPE.toolCallGroup, group })),\n ],\n [mainEventSegments, markerGroups, subAgentGroups, subAgentLanes, toolCallGroups, turnBars],\n );\n\n const barDataset = ({\n label,\n range,\n y,\n color,\n hover,\n thickness,\n order = 1,\n inflateAmount,\n }: {\n label: string;\n range: TimelineGap;\n y: number;\n color: string;\n hover: string;\n thickness: number;\n order?: number;\n inflateAmount?: number;\n }) => ({\n label,\n data: [{ x: getTimelineRange(range), y }] satisfies BarPoint[],\n backgroundColor: color,\n hoverBackgroundColor: hover,\n hoverBorderColor: hover,\n borderWidth: 0,\n borderSkipped: false,\n borderRadius: BAR_RADIUS_PX,\n minBarLength: MARKER_PX,\n barThickness: thickness,\n grouped: false,\n order,\n ...(inflateAmount == null ? {} : { inflateAmount }),\n });\n\n const chartData = useMemo<ChartData<TimelineChartType, Array<BarPoint | MarkerPoint>, string>>(\n () => ({\n datasets: [\n ...turnBars.map(bar =>\n barDataset({\n label: `Turn ${bar.ordinal + 1}`,\n range: bar,\n y: centers[0] ?? 0,\n color: turnFill,\n hover: turnHover,\n thickness: 16,\n }),\n ),\n ...markerGroups.map(group => {\n const type = group.segments.length === 1 ? group.segments[0]?.type : 'system';\n const color = getSessionEventColor(type ?? 'system', isDark);\n return {\n type: 'scatter' as const,\n label: group.segments.map(segment => getSessionEventLabel(segment.type)).join(', '),\n data: [{ x: group.startMs, y: centers[markerRow] ?? 0 }] satisfies MarkerPoint[],\n pointStyle: 'rectRot' as const,\n pointRadius: 5,\n pointHoverRadius: 6,\n clip: false,\n backgroundColor: color,\n hoverBackgroundColor: getSessionEventHoverColor(type ?? 'system', isDark),\n borderWidth: 0,\n order: 0,\n } satisfies ChartDataset<'scatter', MarkerPoint[]>;\n }),\n ...subAgentLanes.flatMap(lane =>\n lane.segments.map(segment =>\n barDataset({\n label: `${getSessionEventLabel(segment.type)}: ${segment.title}`,\n range: segment,\n y: centers[eventRow + 1 + lane.lane] ?? 0,\n color: getSessionEventColor(segment.type, isDark),\n hover: getSessionEventHoverColor(segment.type, isDark),\n thickness: 12,\n order: eventOrder(segment.type),\n inflateAmount: 0.5,\n }),\n ),\n ),\n ...mainEventSegments.map(segment =>\n barDataset({\n label: `${getSessionEventLabel(segment.type)}: ${segment.title}`,\n range: segment,\n y: centers[eventRow] ?? 0,\n color: getSessionEventColor(segment.type, isDark),\n hover: getSessionEventHoverColor(segment.type, isDark),\n thickness: 28,\n order: eventOrder(segment.type),\n inflateAmount: 0.5,\n }),\n ),\n ...toolCallGroups.map(group =>\n barDataset({\n label: 'Parallel tool calls',\n range: group,\n y: centers[eventRow] ?? 0,\n color: getSessionEventColor('tool_call', isDark),\n hover: getSessionEventHoverColor('tool_call', isDark),\n thickness: 28,\n order: eventOrder('tool_call'),\n inflateAmount: 0.5,\n }),\n ),\n ],\n }),\n [\n centers,\n eventRow,\n isDark,\n mainEventSegments,\n markerGroups,\n markerRow,\n subAgentLanes,\n toolCallGroups,\n turnBars,\n turnFill,\n turnHover,\n ],\n );\n\n const turnLabelPlugin = useMemo<Plugin<TimelineChartType>>(\n () => ({\n id: 'turnLabels',\n afterDatasetsDraw(chart) {\n const { ctx } = chart;\n ctx.save();\n ctx.fillStyle = axis;\n ctx.font = '500 10px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n turnBars.forEach((bar, index) => {\n const element = chart.getDatasetMeta(index).data[0];\n if (element == null) return;\n const point = turnBarLabelPoint(element);\n if (point) ctx.fillText(`T${bar.ordinal + 1}`, point.x, point.y);\n });\n ctx.restore();\n },\n }),\n [axis, turnBars],\n );\n const overheadPlugin = useMemo<Plugin<TimelineChartType>>(\n () => ({\n id: 'timelineOverhead',\n afterLayout(chart) {\n const next = Math.round(chart.height - chart.chartArea.height);\n setOverheadPx(previous => (previous === next ? previous : next));\n },\n }),\n [],\n );\n\n const chartOptions = useMemo<ChartOptions<TimelineChartType>>(\n () => ({\n indexAxis: 'y',\n animation: false,\n responsive: true,\n maintainAspectRatio: false,\n onClick: (_event, elements) => {\n const target = chartTargets[elements[0]?.datasetIndex ?? -1];\n if (target?.type === TIMELINE_TYPE.turn) onSelectTurn?.(target.bar.turnIndex);\n },\n onHover: (event, elements) => {\n const hoveredDatasetIndex = elements[0]?.datasetIndex;\n const next = hoveredDatasetIndex == null ? null : (chartTargets[hoveredDatasetIndex] ?? null);\n const native = event.native;\n if (native?.target instanceof HTMLElement) {\n native.target.style.cursor = next?.type === TIMELINE_TYPE.turn ? 'pointer' : 'default';\n }\n if (native instanceof MouseEvent) {\n tooltipCursorXRef.current = native.clientX;\n refreshTooltipAnchor();\n }\n // Pointer between bars keeps the current tooltip; a bar without a tooltip dismisses it.\n if (hoveredDatasetIndex == null) return;\n const nextId = getTimelineHoverTargetId(next);\n if (tooltipIdRef.current === nextId) return;\n tooltipIdRef.current = nextId;\n setTooltipTarget(next);\n if (next == null) {\n setTooltipAnchor(null);\n return;\n }\n refreshTooltipAnchor();\n },\n plugins: { legend: { display: false }, tooltip: { enabled: false } },\n scales: {\n x: {\n type: 'linear',\n position: 'top',\n min: 0,\n max: timelineMaxMs,\n grid: { color: grid },\n border: { color: grid },\n afterBuildTicks: scale => {\n scale.ticks = buildTimelineAxisTicks({ activeTotalMs, turnStartsMs: activeTurnStartsMs, turnGapMs });\n },\n ticks: {\n color: axis,\n align: 'inner',\n autoSkip: false,\n includeBounds: false,\n maxTicksLimit: 9,\n callback: value => {\n const timelineMs = Number(value);\n return timelineMs <= totalMs\n ? formatTimelineAxisDuration(getActiveTimelineMs(timelineMs, timelineGaps))\n : '';\n },\n },\n },\n y: {\n type: 'linear',\n display: false,\n reverse: true,\n offset: false,\n min: 0,\n max: band,\n grid: { display: false },\n },\n },\n }),\n [\n activeTotalMs,\n activeTurnStartsMs,\n axis,\n band,\n chartTargets,\n grid,\n onSelectTurn,\n refreshTooltipAnchor,\n timelineGaps,\n timelineMaxMs,\n totalMs,\n turnGapMs,\n ],\n );\n\n const tooltipTurn = tooltipTarget?.type === TIMELINE_TYPE.turn ? turns[tooltipTarget.bar.turnIndex] : undefined;\n const containerStyle = useMemo<CSSProperties>(() => ({ height: band + overheadPx }), [band, overheadPx]);\n const tooltipContent =\n tooltipTarget?.type === TIMELINE_TYPE.turn && tooltipTurn != null ? (\n <SessionTurnTooltip\n turn={tooltipTurn}\n turnNumber={tooltipTarget.bar.ordinal + 1}\n durationMs={tooltipTarget.bar.durationMs}\n segments={segments.filter(segment => segment.turnIndex === tooltipTarget.bar.turnIndex)}\n />\n ) : tooltipTarget?.type === TIMELINE_TYPE.event && hasSessionEventTooltip(tooltipTarget.segment) ? (\n <SessionEventTooltip\n segment={tooltipTarget.segment}\n subAgentLabel={\n tooltipTarget.segment.type === 'sub_agent'\n ? undefined\n : subAgentLanes.find(lane => lane.threadId === tooltipTarget.segment.threadId)?.track.description\n }\n />\n ) : tooltipTarget?.type === TIMELINE_TYPE.toolCallGroup ? (\n <SessionToolCallGroupTooltip group={tooltipTarget.group} />\n ) : tooltipTarget?.type === TIMELINE_TYPE.markerGroup ? (\n <SessionMarkerGroupTooltip group={tooltipTarget.group} />\n ) : tooltipTarget?.type === TIMELINE_TYPE.subAgentGroup ? (\n <SessionSubAgentGroupTooltip group={tooltipTarget.group} />\n ) : null;\n\n return (\n <div ref={wrapperRef} className=\"w-full\" data-slot=\"agent-session-event-timeline-chart\">\n <LightTooltip\n title={tooltipContent}\n side=\"bottom\"\n triggerClassName=\"block w-full\"\n followCursor\n open={tooltipTarget != null && tooltipContent != null}\n className=\"max-w-[min(25rem,calc(100vw-1rem))] whitespace-normal\"\n anchor={tooltipAnchor}\n >\n <div className=\"w-full\" style={containerStyle} onMouseLeave={clearTooltip}>\n <Chart<TimelineChartType, Array<BarPoint | MarkerPoint>, string>\n type=\"bar\"\n data={chartData}\n options={chartOptions}\n plugins={[turnLabelPlugin, overheadPlugin]}\n />\n </div>\n </LightTooltip>\n </div>\n );\n}\n\ndeclare module '../../theme/SlotsProvider.js' {\n interface AtomSlots {\n AgentSessionEventTimelineChart: ComponentType<AgentSessionEventTimelineChartProps>;\n }\n}\n","'use client';\n\nimport { useThemeMode } from '../../theme/SlotsProvider.js';\nimport { formatCostUsd, formatDurationMs, formatTokenCount } from '../../utils/sessionDisplayFormat.js';\nimport {\n formatTimelineDuration,\n getSessionEventColor,\n getSessionEventTooltipHeading,\n SESSION_EVENT_TOOLTIP_HIDE_DURATION,\n type SessionEventTimelineSegment,\n} from '../../utils/sessionEventTimeline.js';\nimport type {\n TimelineMarkerGroup,\n TimelineSubAgentGroup,\n TimelineToolCallGroup,\n} from '../../utils/sessionEventTimelineChart.js';\nimport type { SessionTurnView } from '../../utils/sessionTurnViews.js';\n\nexport function hasSessionEventTooltip(segment: SessionEventTimelineSegment): boolean {\n return segment.type !== 'system' || segment.description.trim().length > 0;\n}\n\nexport function SessionEventTooltip({\n segment,\n subAgentLabel,\n}: {\n segment: SessionEventTimelineSegment;\n subAgentLabel?: string;\n}) {\n const showDuration = !segment.isMarker && !SESSION_EVENT_TOOLTIP_HIDE_DURATION.has(segment.type);\n const content = segment.description.trim();\n if (segment.type === 'system') {\n if (content.length === 0) return null;\n return (\n <p className=\"max-w-[25rem] whitespace-normal break-words text-xs font-medium text-text-primary\">{content}</p>\n );\n }\n\n return (\n <div className=\"max-h-72 max-w-[25rem] overflow-auto whitespace-normal break-words text-xs\">\n {subAgentLabel != null ? (\n <div className=\"border-b border-border py-1.5 text-text-secondary\">{`Sub-Agent: ${subAgentLabel}`}</div>\n ) : null}\n <div className=\"flex items-center justify-between gap-3 pt-1\">\n <span className={segment.type === 'error' ? 'font-medium text-failure-bg' : 'font-medium text-text-secondary'}>\n {getSessionEventTooltipHeading(segment.type)}\n </span>\n {showDuration ? (\n <span className=\"tabular-nums text-text-secondary\">\n {formatTimelineDuration(segment.endMs - segment.startMs)}\n </span>\n ) : null}\n </div>\n {content.length > 0 ? <p className=\"mt-1.5 line-clamp-6 font-medium text-text-primary\">{content}</p> : null}\n </div>\n );\n}\n\nexport function SessionTurnTooltip({\n turn,\n turnNumber,\n durationMs,\n segments,\n}: {\n turn: SessionTurnView;\n turnNumber: number;\n durationMs: number;\n segments: SessionEventTimelineSegment[];\n}) {\n const isDark = useThemeMode() === 'dark';\n return (\n <div className=\"max-h-72 w-72 max-w-full overflow-auto text-xs text-text-primary\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"font-semibold\">{`Turn ${turnNumber}`}</span>\n <span className=\"tabular-nums text-text-secondary\">{formatDurationMs(durationMs)}</span>\n </div>\n <div className=\"mt-1 flex flex-col text-text-secondary\">\n {turn.totalCostInUsd != null ? <span>{`Cost: ${formatCostUsd(turn.totalCostInUsd)}`}</span> : null}\n {turn.totalTokens != null ? <span>{`Tokens: ${formatTokenCount(turn.totalTokens)}`}</span> : null}\n </div>\n <div className=\"mt-2 border-t border-border pt-2\">\n {segments.map(segment => {\n const label =\n segment.type === 'tool_call' || segment.type === 'sub_agent' ? segment.description : segment.title;\n return (\n <div key={segment.id} className=\"flex min-w-0 items-center gap-1.5\">\n <span\n className=\"size-1.5 shrink-0 rounded-full\"\n style={{ backgroundColor: getSessionEventColor(segment.type, isDark) }}\n />\n <span className=\"min-w-0 flex-1 truncate\">{label}</span>\n {segment.isMarker ? null : (\n <span className=\"ml-auto shrink-0 tabular-nums text-text-secondary\">\n {formatTimelineDuration(segment.endMs - segment.startMs)}\n </span>\n )}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n\nexport function SessionToolCallGroupTooltip({ group }: { group: TimelineToolCallGroup }) {\n return (\n <div className=\"max-h-72 w-80 max-w-full overflow-auto text-xs\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"font-medium text-text-secondary\">Tool calls</span>\n <span className=\"tabular-nums text-text-secondary\">{formatTimelineDuration(group.endMs - group.startMs)}</span>\n </div>\n <div className=\"mt-1.5 border-t border-border pt-1.5\">\n {group.segments.map(segment => (\n <div key={segment.id} className=\"flex items-center justify-between gap-2 py-0.5\">\n <span className=\"min-w-0 truncate font-medium text-text-primary\">\n {segment.description || segment.title}\n </span>\n <span className=\"shrink-0 tabular-nums text-text-secondary\">\n {formatTimelineDuration(segment.endMs - segment.startMs)}\n </span>\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nexport function SessionMarkerGroupTooltip({ group }: { group: TimelineMarkerGroup }) {\n const isDark = useThemeMode() === 'dark';\n const singleSegment = group.segments.length === 1 ? group.segments[0] : undefined;\n if (singleSegment != null) return <SessionEventTooltip segment={singleSegment} />;\n\n return (\n <div className=\"max-h-72 w-80 max-w-full overflow-auto text-xs\">\n <span className=\"font-medium text-text-secondary\">Events</span>\n <div className=\"mt-1.5 border-t border-border pt-1.5\">\n {group.segments.map(segment => (\n <div key={segment.id} className=\"flex min-w-0 items-start gap-1.5 py-0.5\">\n <span\n className=\"mt-1 size-1.5 shrink-0 rounded-full\"\n style={{ backgroundColor: getSessionEventColor(segment.type, isDark) }}\n />\n <div className=\"min-w-0\">\n <div className=\"font-medium text-text-secondary\">{getSessionEventTooltipHeading(segment.type)}</div>\n <div className=\"wrap-break-word font-medium text-text-primary\">\n {segment.description.trim() || segment.title}\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nexport function SessionSubAgentGroupTooltip({ group }: { group: TimelineSubAgentGroup }) {\n return (\n <div className=\"max-h-72 w-80 max-w-full overflow-auto text-xs\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"font-medium text-text-secondary\">Sub-agents</span>\n <span className=\"tabular-nums text-text-secondary\">{formatTimelineDuration(group.endMs - group.startMs)}</span>\n </div>\n <div className=\"mt-1.5 border-t border-border pt-1.5\">\n {group.segments.map((segment, index) => (\n <div key={segment.id} className=\"flex items-center justify-between gap-2 py-0.5\">\n <span className=\"min-w-0 truncate font-medium text-text-primary\">\n {group.segments.length === 1\n ? segment.description || segment.title\n : `Sub-agent ${index + 1}: ${segment.description || segment.title}`}\n </span>\n {group.segments.length === 1 ? null : (\n <span className=\"shrink-0 tabular-nums text-text-secondary\">\n {formatTimelineDuration(segment.endMs - segment.startMs)}\n </span>\n )}\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx"]}
@@ -0,0 +1,323 @@
1
+ "use client";
2
+ import {
3
+ buildSessionResumeHref
4
+ } from "./chunk-2QTH6JHX.js";
5
+ import {
6
+ useOptionalResolvedRoutes
7
+ } from "./chunk-Y6S4OVVQ.js";
8
+ import {
9
+ sessionIsCreateAgent
10
+ } from "./chunk-RDXBMTP5.js";
11
+ import {
12
+ EmptyScreen,
13
+ Skeleton,
14
+ useResourcePermissions,
15
+ useSessionShareSearch,
16
+ useSlot
17
+ } from "./chunk-GG23N2GW.js";
18
+ import "./chunk-T6QQV5LK.js";
19
+ import {
20
+ Icon
21
+ } from "./chunk-3ZW74FHC.js";
22
+ import {
23
+ sessionTimeRangeFromCreatedAt,
24
+ useAgentSessionsServer,
25
+ useOptionalShellMode,
26
+ useServer
27
+ } from "./chunk-2GIZY3JJ.js";
28
+ import "./chunk-M6MHLVSO.js";
29
+ import "./chunk-CG75X77Q.js";
30
+ import {
31
+ cn
32
+ } from "./chunk-JCL3Q7RW.js";
33
+
34
+ // src/atoms/agent-details/AgentSessions.tsx
35
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
36
+ import { Group, Panel, Separator } from "react-resizable-panels";
37
+
38
+ // src/utils/drainListPages.ts
39
+ async function drainListPages({
40
+ fetchPage
41
+ }) {
42
+ const items = [];
43
+ let pageToken;
44
+ do {
45
+ const page = await fetchPage(pageToken);
46
+ items.push(...page.data);
47
+ pageToken = page.nextPageToken;
48
+ } while (pageToken != null && pageToken.length > 0);
49
+ return items;
50
+ }
51
+
52
+ // src/atoms/agent-details/AgentSessions.tsx
53
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
54
+ var LOAD_MORE_ROOT_MARGIN = "96px";
55
+ function sessionTitle(entry) {
56
+ const title = entry.title?.trim();
57
+ return title != null && title.length > 0 ? title : "Untitled session";
58
+ }
59
+ function entryIsMutable(entry) {
60
+ if ("isMutable" in entry && typeof Reflect.get(entry, "isMutable") === "boolean") {
61
+ return Reflect.get(entry, "isMutable") === true;
62
+ }
63
+ return entry.agentName == null;
64
+ }
65
+ function entrySourceType(entry) {
66
+ return "sourceType" in entry && Reflect.get(entry, "sourceType") === "schedule" ? "schedule" : void 0;
67
+ }
68
+ function AgentSessions({ agentId, startTimestamp, endTimestamp, shareView }) {
69
+ const sessionsServer = useAgentSessionsServer();
70
+ const chatServer = useServer();
71
+ const shell = useOptionalShellMode();
72
+ const routes = useOptionalResolvedRoutes();
73
+ const { sessionId: selectedSessionId, updateShareSearch } = useSessionShareSearch();
74
+ const { allows } = useResourcePermissions({
75
+ resourceType: "session",
76
+ resourceIds: selectedSessionId == null ? [] : [selectedSessionId]
77
+ });
78
+ const canResume = allows(selectedSessionId, "MANAGE");
79
+ const AgentSessionListRow = useSlot("AgentSessionListRow");
80
+ const AgentSessionDetailHeader = useSlot("AgentSessionDetailHeader");
81
+ const AgentSessionTimelineContainer = useSlot("AgentSessionTimelineContainer");
82
+ const [entries, setEntries] = useState([]);
83
+ const [nextPageToken, setNextPageToken] = useState();
84
+ const [listLoading, setListLoading] = useState(true);
85
+ const [listLoadingMore, setListLoadingMore] = useState(false);
86
+ const [listLoadMoreFailed, setListLoadMoreFailed] = useState(false);
87
+ const [listFailed, setListFailed] = useState(false);
88
+ const listRequestIdRef = useRef(0);
89
+ const loadMoreInflightRef = useRef(false);
90
+ const [listEl, setListEl] = useState(null);
91
+ const [sentinelEl, setSentinelEl] = useState(null);
92
+ const [detailEvents, setDetailEvents] = useState();
93
+ const [detailSession, setDetailSession] = useState();
94
+ const [detailLoading, setDetailLoading] = useState(false);
95
+ const [detailFailed, setDetailFailed] = useState(false);
96
+ const listRequest = useMemo(
97
+ () => ({
98
+ order: "desc",
99
+ limit: 20,
100
+ ...agentId == null || agentId.length === 0 ? {} : { agentId },
101
+ ...startTimestamp == null ? {} : { startTimestamp },
102
+ ...endTimestamp == null ? {} : { endTimestamp }
103
+ }),
104
+ [agentId, endTimestamp, startTimestamp]
105
+ );
106
+ useEffect(() => {
107
+ const requestId = ++listRequestIdRef.current;
108
+ let cancelled = false;
109
+ loadMoreInflightRef.current = false;
110
+ setNextPageToken(void 0);
111
+ setListLoading(true);
112
+ setListLoadingMore(false);
113
+ setListLoadMoreFailed(false);
114
+ setListFailed(false);
115
+ void sessionsServer.listSessions(listRequest).then((page) => {
116
+ if (cancelled || listRequestIdRef.current !== requestId) return;
117
+ setEntries(page.data);
118
+ setNextPageToken(page.nextPageToken);
119
+ }).catch(() => {
120
+ if (cancelled || listRequestIdRef.current !== requestId) return;
121
+ setEntries([]);
122
+ setNextPageToken(void 0);
123
+ setListFailed(true);
124
+ }).finally(() => {
125
+ if (!cancelled && listRequestIdRef.current === requestId) setListLoading(false);
126
+ });
127
+ return () => {
128
+ cancelled = true;
129
+ };
130
+ }, [listRequest, sessionsServer]);
131
+ const loadMore = useCallback(async () => {
132
+ if (listLoading || nextPageToken == null || loadMoreInflightRef.current) return;
133
+ const requestId = listRequestIdRef.current;
134
+ loadMoreInflightRef.current = true;
135
+ setListLoadingMore(true);
136
+ setListLoadMoreFailed(false);
137
+ try {
138
+ const page = await sessionsServer.listSessions({ ...listRequest, pageToken: nextPageToken });
139
+ if (listRequestIdRef.current !== requestId) return;
140
+ setEntries((current) => [...current, ...page.data]);
141
+ setNextPageToken(page.nextPageToken);
142
+ } catch {
143
+ if (listRequestIdRef.current === requestId) setListLoadMoreFailed(true);
144
+ } finally {
145
+ if (listRequestIdRef.current === requestId) {
146
+ loadMoreInflightRef.current = false;
147
+ setListLoadingMore(false);
148
+ }
149
+ }
150
+ }, [listLoading, listRequest, nextPageToken, sessionsServer]);
151
+ useEffect(() => {
152
+ if (listLoading || nextPageToken == null || listEl == null || sentinelEl == null) return;
153
+ const observer = new IntersectionObserver(
154
+ (observed) => {
155
+ if (observed.some((entry) => entry.isIntersecting)) void loadMore();
156
+ },
157
+ { root: listEl, rootMargin: LOAD_MORE_ROOT_MARGIN }
158
+ );
159
+ observer.observe(sentinelEl);
160
+ return () => observer.disconnect();
161
+ }, [entries.length, listEl, listLoading, loadMore, nextPageToken, sentinelEl]);
162
+ useEffect(() => {
163
+ if (selectedSessionId == null || selectedSessionId.length === 0) {
164
+ setDetailEvents(void 0);
165
+ setDetailSession(void 0);
166
+ setDetailFailed(false);
167
+ setDetailLoading(false);
168
+ return;
169
+ }
170
+ let cancelled = false;
171
+ setDetailLoading(true);
172
+ setDetailFailed(false);
173
+ setDetailEvents(void 0);
174
+ setDetailSession(void 0);
175
+ void Promise.all([
176
+ drainListPages({
177
+ fetchPage: (pageToken) => sessionsServer.listSessionEvents({
178
+ sessionId: selectedSessionId,
179
+ limit: 100,
180
+ ...pageToken == null ? {} : { pageToken }
181
+ })
182
+ }),
183
+ chatServer.getSession({ sessionId: selectedSessionId }).catch(() => void 0)
184
+ ]).then(([itemsNewestFirst, session]) => {
185
+ if (cancelled) return;
186
+ setDetailEvents([...itemsNewestFirst].reverse());
187
+ setDetailSession(session);
188
+ }).catch(() => {
189
+ if (!cancelled) setDetailFailed(true);
190
+ }).finally(() => {
191
+ if (!cancelled) setDetailLoading(false);
192
+ });
193
+ return () => {
194
+ cancelled = true;
195
+ };
196
+ }, [chatServer, selectedSessionId, sessionsServer]);
197
+ const selectSession = (entry) => {
198
+ const pinned = shareView === "sessions" ? sessionTimeRangeFromCreatedAt(entry.createdAt) : null;
199
+ updateShareSearch({
200
+ sessionId: entry.id,
201
+ ...shareView === "sessions" ? { view: "sessions", ...pinned == null ? {} : { timeRange: pinned } } : { agentId: agentId ?? null, tab: "sessions", view: null, timeRange: null }
202
+ });
203
+ };
204
+ const clearSelectedSession = () => {
205
+ if (selectedSessionId == null) return;
206
+ updateShareSearch({ sessionId: null });
207
+ };
208
+ const selectedEntry = entries.find((entry) => entry.id === selectedSessionId);
209
+ const selectedTitle = detailSession != null ? sessionTitle(detailSession) : selectedEntry != null ? sessionTitle(selectedEntry) : selectedSessionId ?? "Untitled session";
210
+ const resumeIsCreateAgent = detailSession != null ? sessionIsCreateAgent(detailSession) : selectedEntry != null ? sessionIsCreateAgent(selectedEntry) : false;
211
+ const resumeIsMutable = detailSession != null ? detailSession.isMutable : selectedEntry != null ? entryIsMutable(selectedEntry) : true;
212
+ const resumeLabel = resumeIsCreateAgent ? "Resume Agent building" : "Resume Chat";
213
+ const resumeHref = selectedSessionId != null && routes != null ? buildSessionResumeHref({ sessionId: selectedSessionId, routes }) : null;
214
+ const handleResume = () => {
215
+ if (!canResume || selectedSessionId == null || shell == null) return;
216
+ const agentName = detailSession?.agentName ?? selectedEntry?.agentName;
217
+ shell.openHistorySession({
218
+ sessionId: selectedSessionId,
219
+ isMutable: resumeIsMutable,
220
+ isCreateAgent: resumeIsCreateAgent,
221
+ ...agentName != null && agentName.length > 0 ? { agentName } : {}
222
+ });
223
+ };
224
+ const resumeProps = resumeHref != null ? { resumeHref, resumeLabel } : shell != null ? { onResume: handleResume, resumeLabel } : {};
225
+ if (!listLoading && !listFailed && entries.length === 0 && (selectedSessionId == null || selectedSessionId.length === 0)) {
226
+ return /* @__PURE__ */ jsx(
227
+ EmptyScreen,
228
+ {
229
+ title: "No Sessions Found",
230
+ description: "There are no sessions available at the moment.",
231
+ className: "bg-primary-bg"
232
+ }
233
+ );
234
+ }
235
+ return /* @__PURE__ */ jsxs(
236
+ Group,
237
+ {
238
+ id: "agent-sessions-split",
239
+ orientation: "horizontal",
240
+ className: "h-full min-h-0 w-full",
241
+ resizeTargetMinimumSize: { coarse: 24, fine: 11 },
242
+ children: [
243
+ /* @__PURE__ */ jsx(Panel, { id: "agent-sessions-list", defaultSize: "35%", minSize: "20%", maxSize: "50%", children: /* @__PURE__ */ jsx("aside", { className: "flex h-full min-h-0 w-full flex-col bg-sidebar-bg", children: /* @__PURE__ */ jsxs("div", { ref: setListEl, className: "scrollbar-none min-h-0 flex-1 overflow-y-auto", children: [
244
+ listLoading ? /* @__PURE__ */ jsx("div", { className: "space-y-2 p-3", role: "status", "aria-label": "Loading sessions", children: ["a", "b", "c"].map((key) => /* @__PURE__ */ jsx(Skeleton, { className: "h-16 rounded-md" }, key)) }) : listFailed ? /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-text-secondary", children: "Sessions could not be loaded." }) : entries.map((entry) => /* @__PURE__ */ jsx(
245
+ AgentSessionListRow,
246
+ {
247
+ title: sessionTitle(entry),
248
+ agentName: entry.agentName ?? void 0,
249
+ sourceType: entrySourceType(entry),
250
+ lastActivityAt: entry.lastActivityAt,
251
+ metrics: entry.metrics,
252
+ active: entry.id === selectedSessionId,
253
+ onSelect: () => selectSession(entry)
254
+ },
255
+ entry.id
256
+ )),
257
+ nextPageToken != null && !listLoading && !listFailed ? /* @__PURE__ */ jsx("div", { ref: setSentinelEl, className: "px-3 py-2", children: listLoadingMore ? /* @__PURE__ */ jsx(Skeleton, { className: "h-16 rounded-md", role: "status", "aria-label": "Loading more sessions" }) : listLoadMoreFailed ? /* @__PURE__ */ jsx(
258
+ "button",
259
+ {
260
+ type: "button",
261
+ className: "h-8 w-full rounded-md border border-border text-xs font-medium text-text-primary hover:bg-ghost-button-hover",
262
+ onClick: () => void loadMore(),
263
+ children: "Retry loading sessions"
264
+ }
265
+ ) : null }) : null
266
+ ] }) }) }),
267
+ /* @__PURE__ */ jsxs(
268
+ Separator,
269
+ {
270
+ id: "agent-sessions-resizer",
271
+ "aria-label": "Resize session list",
272
+ className: "group/resizer relative z-10 w-0 cursor-col-resize focus-visible:outline-none",
273
+ children: [
274
+ /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "absolute inset-y-0 -left-1.25 w-2.75" }),
275
+ /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "absolute inset-y-0 left-0 w-px bg-border transition-colors" }),
276
+ /* @__PURE__ */ jsx(
277
+ "div",
278
+ {
279
+ "aria-hidden": true,
280
+ className: cn(
281
+ "absolute top-1/2 left-0 z-10 flex h-4 w-2 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-xs shadow-sm transition-colors",
282
+ "bg-secondary-button-bg text-text-secondary",
283
+ "group-hover/resizer:bg-primary-button-bg group-hover/resizer:text-primary-button-text",
284
+ "group-active/resizer:bg-primary-button-bg group-active/resizer:text-primary-button-text",
285
+ "group-focus-visible/resizer:bg-primary-button-bg group-focus-visible/resizer:text-primary-button-text"
286
+ ),
287
+ children: /* @__PURE__ */ jsx(Icon, { name: "grip-vertical", size: 10 })
288
+ }
289
+ )
290
+ ]
291
+ }
292
+ ),
293
+ /* @__PURE__ */ jsx(Panel, { id: "agent-session-detail", defaultSize: "65%", minSize: "30%", children: /* @__PURE__ */ jsx("section", { className: "flex h-full min-w-0 flex-col bg-primary-bg", children: selectedSessionId == null ? /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center px-6 text-sm text-text-secondary", children: "Select a session to view details" }) : detailFailed ? /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center px-6 text-sm text-text-secondary", children: "Session details could not be loaded." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
294
+ /* @__PURE__ */ jsx(
295
+ AgentSessionDetailHeader,
296
+ {
297
+ title: selectedTitle,
298
+ sessionId: selectedSessionId,
299
+ agentId,
300
+ createdAt: detailSession?.createdAt ?? selectedEntry?.createdAt,
301
+ view: shareView,
302
+ onClose: clearSelectedSession,
303
+ canResume,
304
+ ...resumeProps
305
+ }
306
+ ),
307
+ detailLoading || detailEvents === void 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col p-4", role: "status", "aria-label": "Loading session details", children: /* @__PURE__ */ jsx(Skeleton, { className: "min-h-64 flex-1 rounded-lg" }) }) : /* @__PURE__ */ jsx(
308
+ AgentSessionTimelineContainer,
309
+ {
310
+ sessionId: selectedSessionId,
311
+ events: detailEvents,
312
+ listMetrics: selectedEntry?.metrics
313
+ }
314
+ )
315
+ ] }) }) })
316
+ ]
317
+ }
318
+ );
319
+ }
320
+ export {
321
+ AgentSessions
322
+ };
323
+ //# sourceMappingURL=AgentSessions-5OTF2BUW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/atoms/agent-details/AgentSessions.tsx","../src/utils/drainListPages.ts"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState, type ComponentType } from 'react';\nimport { Group, Panel, Separator } from 'react-resizable-panels';\n\nimport { useResourcePermissions } from '../../hooks/useResourcePermissions.js';\nimport { useSessionShareSearch } from '../../hooks/useSessionShareSearch.js';\nimport { Icon } from '../../icons/Icon.js';\nimport { buildSessionResumeHref } from '../../routing/paths.js';\nimport { useOptionalResolvedRoutes } from '../../routing/ResolvedRoutesContext.js';\nimport { useAgentSessionsServer, useServer } from '../../server/ServerContext.js';\nimport { useOptionalShellMode } from '../../server/ShellModeContext.js';\nimport type { Session, SessionEventItem, SessionListEntry } from '../../server/types.js';\nimport { useSlot } from '../../theme/SlotsProvider.js';\nimport { drainListPages } from '../../utils/drainListPages.js';\nimport { sessionTimeRangeFromCreatedAt } from '../../utils/sessionShareUrl.js';\nimport { EmptyScreen } from '../EmptyScreen.js';\nimport { cn } from '../lib/cn.js';\nimport { sessionIsCreateAgent } from '../lib/sessionCreateAgent.js';\nimport { Skeleton } from '../primitives/Skeleton.js';\nimport type { AgentSessionsProps } from './types.js';\n\nconst LOAD_MORE_ROOT_MARGIN = '96px';\n\nfunction sessionTitle(entry: Pick<SessionListEntry, 'title'>): string {\n const title = entry.title?.trim();\n return title != null && title.length > 0 ? title : 'Untitled session';\n}\n\nfunction entryIsMutable(entry: SessionListEntry): boolean {\n if ('isMutable' in entry && typeof Reflect.get(entry, 'isMutable') === 'boolean') {\n return Reflect.get(entry, 'isMutable') === true;\n }\n return entry.agentName == null;\n}\n\nfunction entrySourceType(entry: SessionListEntry): 'schedule' | undefined {\n return 'sourceType' in entry && Reflect.get(entry, 'sourceType') === 'schedule' ? 'schedule' : undefined;\n}\n\nexport function AgentSessions({ agentId, startTimestamp, endTimestamp, shareView }: AgentSessionsProps) {\n const sessionsServer = useAgentSessionsServer();\n const chatServer = useServer();\n const shell = useOptionalShellMode();\n const routes = useOptionalResolvedRoutes();\n const { sessionId: selectedSessionId, updateShareSearch } = useSessionShareSearch();\n const { allows } = useResourcePermissions({\n resourceType: 'session',\n resourceIds: selectedSessionId == null ? [] : [selectedSessionId],\n });\n const canResume = allows(selectedSessionId, 'MANAGE');\n\n const AgentSessionListRow = useSlot('AgentSessionListRow');\n const AgentSessionDetailHeader = useSlot('AgentSessionDetailHeader');\n const AgentSessionTimelineContainer = useSlot('AgentSessionTimelineContainer');\n\n const [entries, setEntries] = useState<SessionListEntry[]>([]);\n const [nextPageToken, setNextPageToken] = useState<string | undefined>();\n const [listLoading, setListLoading] = useState(true);\n const [listLoadingMore, setListLoadingMore] = useState(false);\n const [listLoadMoreFailed, setListLoadMoreFailed] = useState(false);\n const [listFailed, setListFailed] = useState(false);\n const listRequestIdRef = useRef(0);\n const loadMoreInflightRef = useRef(false);\n const [listEl, setListEl] = useState<HTMLDivElement | null>(null);\n const [sentinelEl, setSentinelEl] = useState<HTMLDivElement | null>(null);\n const [detailEvents, setDetailEvents] = useState<SessionEventItem[]>();\n const [detailSession, setDetailSession] = useState<Session>();\n const [detailLoading, setDetailLoading] = useState(false);\n const [detailFailed, setDetailFailed] = useState(false);\n\n const listRequest = useMemo(\n () => ({\n order: 'desc' as const,\n limit: 20,\n ...(agentId == null || agentId.length === 0 ? {} : { agentId }),\n ...(startTimestamp == null ? {} : { startTimestamp }),\n ...(endTimestamp == null ? {} : { endTimestamp }),\n }),\n [agentId, endTimestamp, startTimestamp],\n );\n\n useEffect(() => {\n const requestId = ++listRequestIdRef.current;\n let cancelled = false;\n loadMoreInflightRef.current = false;\n setNextPageToken(undefined);\n setListLoading(true);\n setListLoadingMore(false);\n setListLoadMoreFailed(false);\n setListFailed(false);\n void sessionsServer\n .listSessions(listRequest)\n .then(page => {\n if (cancelled || listRequestIdRef.current !== requestId) return;\n setEntries(page.data);\n setNextPageToken(page.nextPageToken);\n })\n .catch(() => {\n if (cancelled || listRequestIdRef.current !== requestId) return;\n setEntries([]);\n setNextPageToken(undefined);\n setListFailed(true);\n })\n .finally(() => {\n if (!cancelled && listRequestIdRef.current === requestId) setListLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [listRequest, sessionsServer]);\n\n const loadMore = useCallback(async () => {\n // A ref, not `listLoadingMore`: the observer can fire twice before a re-render.\n if (listLoading || nextPageToken == null || loadMoreInflightRef.current) return;\n const requestId = listRequestIdRef.current;\n loadMoreInflightRef.current = true;\n setListLoadingMore(true);\n setListLoadMoreFailed(false);\n try {\n const page = await sessionsServer.listSessions({ ...listRequest, pageToken: nextPageToken });\n if (listRequestIdRef.current !== requestId) return;\n setEntries(current => [...current, ...page.data]);\n setNextPageToken(page.nextPageToken);\n } catch {\n if (listRequestIdRef.current === requestId) setListLoadMoreFailed(true);\n } finally {\n if (listRequestIdRef.current === requestId) {\n loadMoreInflightRef.current = false;\n setListLoadingMore(false);\n }\n }\n }, [listLoading, listRequest, nextPageToken, sessionsServer]);\n\n // `entries.length` re-arms the observer: an already-intersecting sentinel emits no new entry.\n useEffect(() => {\n if (listLoading || nextPageToken == null || listEl == null || sentinelEl == null) return;\n\n const observer = new IntersectionObserver(\n observed => {\n if (observed.some(entry => entry.isIntersecting)) void loadMore();\n },\n { root: listEl, rootMargin: LOAD_MORE_ROOT_MARGIN },\n );\n observer.observe(sentinelEl);\n return () => observer.disconnect();\n }, [entries.length, listEl, listLoading, loadMore, nextPageToken, sentinelEl]);\n\n useEffect(() => {\n if (selectedSessionId == null || selectedSessionId.length === 0) {\n setDetailEvents(undefined);\n setDetailSession(undefined);\n setDetailFailed(false);\n setDetailLoading(false);\n return;\n }\n\n let cancelled = false;\n setDetailLoading(true);\n setDetailFailed(false);\n setDetailEvents(undefined);\n setDetailSession(undefined);\n\n void Promise.all([\n drainListPages({\n fetchPage: pageToken =>\n sessionsServer.listSessionEvents({\n sessionId: selectedSessionId,\n limit: 100,\n ...(pageToken == null ? {} : { pageToken }),\n }),\n }),\n chatServer.getSession({ sessionId: selectedSessionId }).catch(() => undefined),\n ])\n .then(([itemsNewestFirst, session]) => {\n if (cancelled) return;\n setDetailEvents([...itemsNewestFirst].reverse());\n setDetailSession(session);\n })\n .catch(() => {\n if (!cancelled) setDetailFailed(true);\n })\n .finally(() => {\n if (!cancelled) setDetailLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [chatServer, selectedSessionId, sessionsServer]);\n\n const selectSession = (entry: SessionListEntry) => {\n const pinned = shareView === 'sessions' ? sessionTimeRangeFromCreatedAt(entry.createdAt) : null;\n updateShareSearch({\n sessionId: entry.id,\n ...(shareView === 'sessions'\n ? { view: 'sessions', ...(pinned == null ? {} : { timeRange: pinned }) }\n : { agentId: agentId ?? null, tab: 'sessions', view: null, timeRange: null }),\n });\n };\n\n const clearSelectedSession = () => {\n if (selectedSessionId == null) return;\n updateShareSearch({ sessionId: null });\n };\n\n const selectedEntry = entries.find(entry => entry.id === selectedSessionId);\n const selectedTitle =\n detailSession != null\n ? sessionTitle(detailSession)\n : selectedEntry != null\n ? sessionTitle(selectedEntry)\n : (selectedSessionId ?? 'Untitled session');\n\n const resumeIsCreateAgent =\n detailSession != null\n ? sessionIsCreateAgent(detailSession)\n : selectedEntry != null\n ? sessionIsCreateAgent(selectedEntry)\n : false;\n const resumeIsMutable =\n detailSession != null ? detailSession.isMutable : selectedEntry != null ? entryIsMutable(selectedEntry) : true;\n const resumeLabel = resumeIsCreateAgent ? 'Resume Agent building' : 'Resume Chat';\n const resumeHref =\n selectedSessionId != null && routes != null\n ? buildSessionResumeHref({ sessionId: selectedSessionId, routes })\n : null;\n\n const handleResume = () => {\n if (!canResume || selectedSessionId == null || shell == null) return;\n const agentName = detailSession?.agentName ?? selectedEntry?.agentName;\n shell.openHistorySession({\n sessionId: selectedSessionId,\n isMutable: resumeIsMutable,\n isCreateAgent: resumeIsCreateAgent,\n ...(agentName != null && agentName.length > 0 ? { agentName } : {}),\n });\n };\n\n const resumeProps =\n resumeHref != null ? { resumeHref, resumeLabel } : shell != null ? { onResume: handleResume, resumeLabel } : {};\n\n // Full empty only when nothing is selected — keep the detail pane for deep-linked sessionIds\n // (filters/time range can empty the list while share state still points at a session).\n if (\n !listLoading &&\n !listFailed &&\n entries.length === 0 &&\n (selectedSessionId == null || selectedSessionId.length === 0)\n ) {\n return (\n <EmptyScreen\n title=\"No Sessions Found\"\n description=\"There are no sessions available at the moment.\"\n className=\"bg-primary-bg\"\n />\n );\n }\n\n return (\n <Group\n id=\"agent-sessions-split\"\n orientation=\"horizontal\"\n className=\"h-full min-h-0 w-full\"\n resizeTargetMinimumSize={{ coarse: 24, fine: 11 }}\n >\n <Panel id=\"agent-sessions-list\" defaultSize=\"35%\" minSize=\"20%\" maxSize=\"50%\">\n <aside className=\"flex h-full min-h-0 w-full flex-col bg-sidebar-bg\">\n <div ref={setListEl} className=\"scrollbar-none min-h-0 flex-1 overflow-y-auto\">\n {listLoading ? (\n <div className=\"space-y-2 p-3\" role=\"status\" aria-label=\"Loading sessions\">\n {['a', 'b', 'c'].map(key => (\n <Skeleton key={key} className=\"h-16 rounded-md\" />\n ))}\n </div>\n ) : listFailed ? (\n <p className=\"px-3 py-6 text-center text-xs text-text-secondary\">Sessions could not be loaded.</p>\n ) : (\n entries.map(entry => (\n <AgentSessionListRow\n key={entry.id}\n title={sessionTitle(entry)}\n agentName={entry.agentName ?? undefined}\n sourceType={entrySourceType(entry)}\n lastActivityAt={entry.lastActivityAt}\n metrics={entry.metrics}\n active={entry.id === selectedSessionId}\n onSelect={() => selectSession(entry)}\n />\n ))\n )}\n\n {nextPageToken != null && !listLoading && !listFailed ? (\n <div ref={setSentinelEl} className=\"px-3 py-2\">\n {listLoadingMore ? (\n <Skeleton className=\"h-16 rounded-md\" role=\"status\" aria-label=\"Loading more sessions\" />\n ) : listLoadMoreFailed ? (\n <button\n type=\"button\"\n className=\"h-8 w-full rounded-md border border-border text-xs font-medium text-text-primary hover:bg-ghost-button-hover\"\n onClick={() => void loadMore()}\n >\n Retry loading sessions\n </button>\n ) : null}\n </div>\n ) : null}\n </div>\n </aside>\n </Panel>\n\n <Separator\n id=\"agent-sessions-resizer\"\n aria-label=\"Resize session list\"\n className=\"group/resizer relative z-10 w-0 cursor-col-resize focus-visible:outline-none\"\n >\n <div aria-hidden className=\"absolute inset-y-0 -left-1.25 w-2.75\" />\n <div aria-hidden className=\"absolute inset-y-0 left-0 w-px bg-border transition-colors\" />\n <div\n aria-hidden\n className={cn(\n 'absolute top-1/2 left-0 z-10 flex h-4 w-2 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-xs shadow-sm transition-colors',\n 'bg-secondary-button-bg text-text-secondary',\n 'group-hover/resizer:bg-primary-button-bg group-hover/resizer:text-primary-button-text',\n 'group-active/resizer:bg-primary-button-bg group-active/resizer:text-primary-button-text',\n 'group-focus-visible/resizer:bg-primary-button-bg group-focus-visible/resizer:text-primary-button-text',\n )}\n >\n <Icon name=\"grip-vertical\" size={10} />\n </div>\n </Separator>\n\n <Panel id=\"agent-session-detail\" defaultSize=\"65%\" minSize=\"30%\">\n <section className=\"flex h-full min-w-0 flex-col bg-primary-bg\">\n {selectedSessionId == null ? (\n <div className=\"flex flex-1 items-center justify-center px-6 text-sm text-text-secondary\">\n Select a session to view details\n </div>\n ) : detailFailed ? (\n <div className=\"flex flex-1 items-center justify-center px-6 text-sm text-text-secondary\">\n Session details could not be loaded.\n </div>\n ) : (\n <>\n <AgentSessionDetailHeader\n title={selectedTitle}\n sessionId={selectedSessionId}\n agentId={agentId}\n createdAt={detailSession?.createdAt ?? selectedEntry?.createdAt}\n view={shareView}\n onClose={clearSelectedSession}\n canResume={canResume}\n {...resumeProps}\n />\n {detailLoading || detailEvents === undefined ? (\n <div className=\"flex flex-1 flex-col p-4\" role=\"status\" aria-label=\"Loading session details\">\n <Skeleton className=\"min-h-64 flex-1 rounded-lg\" />\n </div>\n ) : (\n <AgentSessionTimelineContainer\n sessionId={selectedSessionId}\n events={detailEvents}\n listMetrics={selectedEntry?.metrics}\n />\n )}\n </>\n )}\n </section>\n </Panel>\n </Group>\n );\n}\n\ndeclare module '../../theme/SlotsProvider.js' {\n interface AtomSlots {\n AgentSessions: ComponentType<AgentSessionsProps>;\n }\n}\n","import type { ListResult } from '../server/types.js';\n\n/** Drain token-paginated list endpoints until `nextPageToken` is exhausted. */\nexport async function drainListPages<T>({\n fetchPage,\n}: {\n fetchPage: (pageToken?: string) => Promise<ListResult<T>>;\n}): Promise<T[]> {\n const items: T[] = [];\n let pageToken: string | undefined;\n do {\n const page = await fetchPage(pageToken);\n items.push(...page.data);\n pageToken = page.nextPageToken;\n } while (pageToken != null && pageToken.length > 0);\n return items;\n}\n"],"mappings":"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","names":[]}