@railtownai/railtracks-visualizer 0.0.27 → 0.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -14732,33 +14732,18 @@ function cn(...inputs) {
14732
14732
  return str.split(/[-_\s]+/).map((word)=>word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
14733
14733
  }
14734
14734
  /**
14735
- * Formats a currency value
14736
- * @param value - The value to format
14737
- * @returns The formatted currency string
14738
- */ function formatCurrency(value) {
14735
+ * Formats a currency value (USD dollars)
14736
+ * @param value - The dollar value to format
14737
+ * @param precision - The number of decimal places to show. Defaults to 3.
14738
+ * @returns The formatted dollar string (eg: $123.002)
14739
+ */ function formatCurrency(value, precision = 3) {
14739
14740
  if (value === null || value === undefined) {
14740
- return "$0.00";
14741
- }
14742
- // For very small values (less than 0.01), show more decimal places
14743
- if (Math.abs(value) < 0.01 && value !== 0) {
14744
- const decimalPlaces = value.toString().split(".")[1]?.length || 0;
14745
- const maxFractionDigits = Math.max(3, Math.min(decimalPlaces, 2));
14746
- return new Intl.NumberFormat("en-US", {
14747
- style: "currency",
14748
- currency: "USD",
14749
- minimumFractionDigits: Math.min(3, maxFractionDigits),
14750
- maximumFractionDigits: maxFractionDigits
14751
- }).format(value);
14752
- }
14753
- // For values with more than 2 decimal places, show them
14754
- const decimalPlaces = value.toString().split(".")[1]?.length || 0;
14755
- const maxFractionDigits = Math.max(2, Math.min(decimalPlaces, 2));
14756
- return new Intl.NumberFormat("en-US", {
14757
- style: "currency",
14758
- currency: "USD",
14759
- minimumFractionDigits: 2,
14760
- maximumFractionDigits: maxFractionDigits
14761
- }).format(value);
14741
+ return "$0.000";
14742
+ }
14743
+ // Format the dollar value with sp ecified precision
14744
+ const formatted = Math.abs(value).toFixed(precision);
14745
+ const sign = value < 0 ? "-" : "";
14746
+ return `${sign}$${formatted}`;
14762
14747
  }
14763
14748
  /**
14764
14749
  * Formats latency in a human-readable format
@@ -14771,7 +14756,7 @@ function cn(...inputs) {
14771
14756
  return `${latency.toFixed(1)}s`;
14772
14757
  } else {
14773
14758
  const minutes = Math.floor(latency / 60);
14774
- const seconds = Math.round(latency % 60 / 1000);
14759
+ const seconds = Math.round(latency % 60);
14775
14760
  return `${minutes}m ${seconds}s`;
14776
14761
  }
14777
14762
  }
@@ -15489,614 +15474,250 @@ const AnthropicIcon = ({ width = "1.5rem", height = "1.5rem" })=>/*#__PURE__*/ R
15489
15474
  strokeWidth: "0.25"
15490
15475
  }));
15491
15476
 
15492
- const DEFAULT_COUNTUP_DURATION = 1.2;
15493
- // Helper function to get node icon
15494
- const getNodeIcon$1 = (nodeType, modelProvider)=>{
15495
- if (nodeType === "tool") {
15496
- return "🔧";
15497
- }
15498
- if (nodeType === "coordinator") {
15499
- return "🎯";
15500
- }
15501
- if (nodeType === "agent") {
15502
- if (modelProvider === "OpenAI") {
15503
- return /*#__PURE__*/ React.createElement(OpenAIIcon, null);
15504
- }
15505
- if (modelProvider === "Anthropic") {
15506
- return /*#__PURE__*/ React.createElement(AnthropicIcon, null);
15507
- }
15508
- if (modelProvider === "Google" || modelProvider === "Vertex_AI") {
15509
- return /*#__PURE__*/ React.createElement(GoogleIcon, null);
15510
- }
15511
- }
15512
- return "🤖";
15513
- };
15514
- const NodeDetailsPopover = ({ isVisible, onClose, nodeData, triggerRef })=>{
15515
- const [position, setPosition] = React.useState({
15516
- top: 0,
15517
- left: 0,
15518
- arrowPosition: "right"
15519
- });
15520
- // Calculate popover position based on trigger element
15521
- React.useEffect(()=>{
15522
- if (isVisible && triggerRef.current) {
15523
- const rect = triggerRef.current.getBoundingClientRect();
15524
- const viewportWidth = window.innerWidth;
15525
- const viewportHeight = window.innerHeight;
15526
- const popoverWidth = 400; // Match the width from styled component
15527
- const popoverHeight = 600; // Approximate max height
15528
- const gap = 12; // Gap between node and popover
15529
- // Check if the rect is valid (has non-zero dimensions and is in viewport)
15530
- const isValidRect = rect.width > 0 && rect.height > 0 && rect.top >= 0 && rect.left >= 0;
15531
- if (isValidRect) {
15532
- // Normal positioning logic for ReactFlow
15533
- let left = rect.right + gap;
15534
- let top = rect.top;
15535
- let arrowPosition = "right"; // Arrow points right (popover is to the right)
15536
- // If popover would go off-screen, position it to the left of the node
15537
- if (left + popoverWidth > viewportWidth) {
15538
- left = rect.left - popoverWidth - gap;
15539
- arrowPosition = "left"; // Arrow points left (popover is to the left)
15540
- }
15541
- // Ensure popover doesn't go off the top or bottom of the viewport
15542
- if (top < 0) {
15543
- top = 20; // Small margin from top
15544
- } else if (top + popoverHeight > viewportHeight) {
15545
- top = viewportHeight - popoverHeight - 20; // Small margin from bottom
15546
- }
15547
- setPosition({
15548
- top,
15549
- left,
15550
- arrowPosition
15551
- });
15552
- } else {
15553
- // Fallback positioning for isolated environments (like Storybook)
15554
- // Center the popover in the viewport
15555
- const centerLeft = Math.max(20, (viewportWidth - popoverWidth) / 2);
15556
- const centerTop = Math.max(20, (viewportHeight - popoverHeight) / 2);
15557
- setPosition({
15558
- top: centerTop,
15559
- left: centerLeft,
15560
- arrowPosition: "none" // No arrow in fallback mode
15561
- });
15562
- }
15477
+ const ExpandableTextarea = ({ label, content, isExpanded, onToggle })=>{
15478
+ const { theme } = useTheme();
15479
+ const themeColors = theme?.colors || {
15480
+ muted: "hsl(210 40% 96%)",
15481
+ mutedForeground: "hsl(215.4 16.3% 46.9%)",
15482
+ border: "hsl(214.3 31.8% 91.4%)",
15483
+ foreground: "hsl(222.2 84% 4.9%)"
15484
+ };
15485
+ const displayContent = isExpanded ? content : content?.slice(0, 100) + (content?.length > 100 ? "..." : "");
15486
+ return /*#__PURE__*/ React.createElement(ExpandableSection, null, /*#__PURE__*/ React.createElement(ExpandableHeader, {
15487
+ onClick: (e)=>{
15488
+ e.stopPropagation();
15489
+ onToggle(e);
15490
+ },
15491
+ onMouseEnter: (e)=>{
15492
+ e.currentTarget.style.backgroundColor = themeColors.muted;
15493
+ },
15494
+ onMouseLeave: (e)=>{
15495
+ e.currentTarget.style.backgroundColor = "transparent";
15563
15496
  }
15564
- }, [
15565
- isVisible,
15566
- triggerRef
15567
- ]);
15568
- // Handle ESC key to close popover
15569
- React.useEffect(()=>{
15570
- const handleEscKey = (event)=>{
15571
- if (event.key === "Escape") {
15572
- onClose();
15573
- }
15574
- };
15575
- if (isVisible) {
15576
- document.addEventListener("keydown", handleEscKey);
15577
- return ()=>document.removeEventListener("keydown", handleEscKey);
15497
+ }, /*#__PURE__*/ React.createElement(ExpandableLabel, null, label), /*#__PURE__*/ React.createElement(ChevronIcon, null, isExpanded ? /*#__PURE__*/ React.createElement(ChevronDown, {
15498
+ style: {
15499
+ width: "12px",
15500
+ height: "12px",
15501
+ color: themeColors.mutedForeground
15578
15502
  }
15579
- }, [
15580
- isVisible,
15581
- onClose
15582
- ]);
15583
- // Handle click outside to close popover
15584
- React.useEffect(()=>{
15585
- const handleClickOutside = (event)=>{
15586
- if (isVisible && triggerRef.current && !triggerRef.current.contains(event.target) && !event.target.closest("[data-popover-content]")) {
15587
- onClose();
15588
- }
15589
- };
15590
- if (isVisible) {
15591
- document.addEventListener("mousedown", handleClickOutside);
15592
- return ()=>document.removeEventListener("mousedown", handleClickOutside);
15503
+ }) : /*#__PURE__*/ React.createElement(ChevronRight, {
15504
+ style: {
15505
+ width: "12px",
15506
+ height: "12px",
15507
+ color: themeColors.mutedForeground
15593
15508
  }
15594
- }, [
15595
- isVisible,
15596
- onClose,
15597
- triggerRef
15598
- ]);
15599
- if (!isVisible) return null;
15600
- const llOverviewDetails = getOverviewLlmDetails(nodeData.details?.internals?.llm_details || []);
15601
- const totalCost = sumTotalCost(nodeData.details?.internals?.llm_details || []);
15602
- const totalInputTokens = sumTotalInputTokens(nodeData.details?.internals?.llm_details || []);
15603
- const totalOutputTokens = sumTotalOutputTokens(nodeData.details?.internals?.llm_details || []);
15604
- const totalLatency = sumTotalLatency(nodeData.details?.internals?.llm_details || []);
15605
- const popoverContent = /*#__PURE__*/ React.createElement(PopoverPortal, {
15509
+ }))), /*#__PURE__*/ React.createElement(ExpandableTextareaElement, {
15510
+ onClick: (e)=>{
15511
+ e.stopPropagation();
15512
+ },
15513
+ value: displayContent || "",
15514
+ readOnly: true,
15515
+ rows: isExpanded ? Math.max(3, Math.max(content?.split("\n").length || 0, Math.ceil((content?.length || 0) / 60))) : 2,
15606
15516
  style: {
15607
- top: position.top,
15608
- left: position.left
15517
+ border: `1px solid ${themeColors.border}`,
15518
+ backgroundColor: themeColors.muted,
15519
+ color: themeColors.foreground
15609
15520
  }
15610
- }, /*#__PURE__*/ React.createElement(PopoverContent, {
15611
- "data-popover-content": true,
15612
- $arrowPosition: position.arrowPosition
15613
- }, /*#__PURE__*/ React.createElement(PopoverHeader, null, /*#__PURE__*/ React.createElement(PopoverTitle, null, /*#__PURE__*/ React.createElement(NodeIcon$3, null, getNodeIcon$1(nodeData.nodeType || "Agent", llOverviewDetails?.model_provider)), /*#__PURE__*/ React.createElement("span", null, nodeData.label || "Agent Node")), /*#__PURE__*/ React.createElement(PopoverHeaderButtons, null, /*#__PURE__*/ React.createElement(CloseButton, {
15614
- onClick: onClose
15615
- }, /*#__PURE__*/ React.createElement(X, {
15616
- size: 16
15617
- })))), /*#__PURE__*/ React.createElement(PopoverBody, null, llOverviewDetails && /*#__PURE__*/ React.createElement(Section, null, /*#__PURE__*/ React.createElement(InfoGrid, null, /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, "Model"), /*#__PURE__*/ React.createElement(InfoValue, null, llOverviewDetails.model_name)), /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, "Provider"), /*#__PURE__*/ React.createElement(InfoValue, null, llOverviewDetails.model_provider)), /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, "Input Tokens"), /*#__PURE__*/ React.createElement(InfoValue, null, totalInputTokens ? /*#__PURE__*/ React.createElement(CountUp, {
15618
- end: totalInputTokens,
15619
- duration: DEFAULT_COUNTUP_DURATION,
15620
- separator: ",",
15621
- useEasing: true
15622
- }) : "N/A")), /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, "Output Tokens"), /*#__PURE__*/ React.createElement(InfoValue, null, totalOutputTokens ? /*#__PURE__*/ React.createElement(CountUp, {
15623
- end: totalOutputTokens,
15624
- duration: DEFAULT_COUNTUP_DURATION,
15625
- separator: ",",
15626
- useEasing: true
15627
- }) : "N/A")), /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, "Total Cost"), /*#__PURE__*/ React.createElement(InfoValue, null, "~", formatCurrency(totalCost))), llOverviewDetails.system_fingerprint && /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, "System Fingerprint"), /*#__PURE__*/ React.createElement(InfoValue, null, llOverviewDetails.system_fingerprint)), totalLatency > 0 && /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, "Total Latency"), /*#__PURE__*/ React.createElement(InfoValue, null, formatLatency(totalLatency))))), nodeData.details?.internals?.llm_details.length > 0 && /*#__PURE__*/ React.createElement(Section, null, /*#__PURE__*/ React.createElement("table", null, /*#__PURE__*/ React.createElement("thead", null, /*#__PURE__*/ React.createElement("tr", null, /*#__PURE__*/ React.createElement("th", null, "#"), /*#__PURE__*/ React.createElement("th", {
15521
+ }));
15522
+ };
15523
+ // Styled components
15524
+ const ExpandableSection = styled.div`
15525
+ width: 100%;
15526
+ `;
15527
+ const ExpandableHeader = styled.div`
15528
+ display: flex;
15529
+ justify-content: space-between;
15530
+ align-items: center;
15531
+ padding: 0.25rem 0;
15532
+ cursor: pointer;
15533
+ user-select: none;
15534
+ border-radius: 0.25rem;
15535
+ padding-left: 0.25rem;
15536
+ padding-right: 0.25rem;
15537
+
15538
+ &:hover {
15539
+ background-color: transparent;
15540
+ }
15541
+ `;
15542
+ const ExpandableLabel = styled.span`
15543
+ font-size: 0.75rem;
15544
+ font-weight: 500;
15545
+ color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
15546
+ `;
15547
+ const ExpandableTextareaElement = styled.textarea`
15548
+ box-sizing: border-box;
15549
+ width: 100%;
15550
+ border-radius: 0.25rem;
15551
+ padding: 0.5rem;
15552
+ resize: none;
15553
+ min-height: 40px;
15554
+ font-family: inherit;
15555
+
15556
+ &:focus {
15557
+ outline: none;
15558
+ border-color: ${(props)=>props.theme?.colors?.primary || "hsl(221.2 83.2% 53.3%)"};
15559
+ box-shadow: 0 0 0 1px ${(props)=>props.theme?.colors?.primary || "hsl(221.2 83.2% 53.3%)"};
15560
+ }
15561
+
15562
+ transition: all 0.2s ease-in-out;
15563
+ `;
15564
+ const ChevronIcon = styled.div`
15565
+ transition: transform 0.2s ease-in-out;
15566
+ `;
15567
+
15568
+ const CodeBlock = ({ content, language = "text", showHeader = false })=>{
15569
+ const { theme } = useTheme();
15570
+ const themeColors = theme?.colors || {
15571
+ muted: "hsl(210 40% 96%)",
15572
+ mutedForeground: "hsl(215.4 16.3% 46.9%)",
15573
+ border: "hsl(214.3 31.8% 91.4%)",
15574
+ foreground: "hsl(222.2 84% 4.9%)",
15575
+ background: "hsl(0 0% 100%)"
15576
+ };
15577
+ return /*#__PURE__*/ React.createElement(CodeBlockContainer, {
15628
15578
  style: {
15629
- textAlign: "right"
15579
+ width: "100%",
15580
+ border: `1px solid ${themeColors.border}`,
15581
+ backgroundColor: themeColors.muted,
15582
+ color: themeColors.foreground
15630
15583
  }
15631
- }, "Input Tokens"), /*#__PURE__*/ React.createElement("th", {
15584
+ }, showHeader && /*#__PURE__*/ React.createElement(CodeBlockHeader, {
15632
15585
  style: {
15633
- textAlign: "right"
15586
+ borderBottom: `1px solid ${themeColors.border}`,
15587
+ backgroundColor: themeColors.background
15634
15588
  }
15635
- }, "Output Tokens"), /*#__PURE__*/ React.createElement("th", {
15589
+ }, /*#__PURE__*/ React.createElement(CodeBlockLanguage, {
15636
15590
  style: {
15637
- textAlign: "right"
15591
+ color: themeColors.mutedForeground
15638
15592
  }
15639
- }, "Total Cost"), /*#__PURE__*/ React.createElement("th", {
15593
+ }, language)), /*#__PURE__*/ React.createElement(CodeBlockContent, {
15640
15594
  style: {
15641
- textAlign: "right"
15595
+ color: themeColors.foreground
15642
15596
  }
15643
- }, "Latency"))), /*#__PURE__*/ React.createElement("tbody", null, nodeData.details?.internals?.llm_details.map((details, index)=>/*#__PURE__*/ React.createElement("tr", null, /*#__PURE__*/ React.createElement("td", null, index + 1), /*#__PURE__*/ React.createElement("td", {
15644
- style: {
15645
- textAlign: "right"
15646
- }
15647
- }, details.input_tokens ? /*#__PURE__*/ React.createElement(CountUp, {
15648
- end: details.input_tokens,
15649
- duration: DEFAULT_COUNTUP_DURATION,
15650
- separator: ",",
15651
- useEasing: true
15652
- }) : "N/A"), /*#__PURE__*/ React.createElement("td", {
15653
- style: {
15654
- textAlign: "right"
15655
- }
15656
- }, details.output_tokens ? /*#__PURE__*/ React.createElement(CountUp, {
15657
- end: details.output_tokens,
15658
- duration: DEFAULT_COUNTUP_DURATION,
15659
- separator: ",",
15660
- useEasing: true
15661
- }) : "N/A"), /*#__PURE__*/ React.createElement("td", {
15662
- style: {
15663
- textAlign: "right"
15664
- }
15665
- }, details.total_cost ? formatCurrency(details.total_cost) : "N/A"), /*#__PURE__*/ React.createElement("td", {
15666
- style: {
15667
- textAlign: "right"
15668
- }
15669
- }, details.latency ? formatLatency(details.latency) : "N/A")))))))));
15670
- // Use React Portal to render outside of ReactFlow container
15671
- return /*#__PURE__*/ ReactDOM.createPortal(popoverContent, document.body);
15597
+ }, content));
15672
15598
  };
15673
- // Styled components
15674
- const PopoverPortal = styled.div`
15675
- position: fixed;
15676
- z-index: 99999;
15677
- pointer-events: none;
15678
- `;
15679
- const PopoverContent = styled.div`
15680
- width: 400px;
15681
- max-height: 600px;
15682
- background-color: ${(props)=>props.theme?.colors?.background || "hsl(0 0% 100%)"};
15683
- border: 1px solid ${(props)=>props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
15684
- border-radius: 0.5rem;
15685
- box-shadow:
15686
- 0 10px 15px -3px rgba(0, 0, 0, 0.1),
15687
- 0 4px 6px -2px rgba(0, 0, 0, 0.05);
15688
- z-index: 99999;
15689
- pointer-events: auto;
15690
- animation: popoverSlideIn 200ms ease-out;
15691
-
15692
- @keyframes popoverSlideIn {
15693
- from {
15694
- transform: translateX(-10px);
15695
- opacity: 0;
15696
- }
15697
- to {
15698
- transform: translateX(0);
15699
- opacity: 1;
15700
- }
15701
- }
15702
-
15703
- /* Arrow pointing to the node - only show when not in fallback mode */
15704
- ${(props)=>props.$arrowPosition !== "none" && `
15705
- &::before {
15706
- content: "";
15707
- position: absolute;
15708
- top: 20px;
15709
- width: 0;
15710
- height: 0;
15711
- border-top: 6px solid transparent;
15712
- border-bottom: 6px solid transparent;
15713
- ${props.$arrowPosition === "right" ? `
15714
- left: -6px;
15715
- border-right: 6px solid ${props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
15716
- ` : `
15717
- right: -6px;
15718
- border-left: 6px solid ${props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
15719
- `}
15720
- }
15721
-
15722
- &::after {
15723
- content: "";
15724
- position: absolute;
15725
- top: 20px;
15726
- width: 0;
15727
- height: 0;
15728
- border-top: 6px solid transparent;
15729
- border-bottom: 6px solid transparent;
15730
- ${props.$arrowPosition === "right" ? `
15731
- left: -5px;
15732
- border-right: 6px solid ${props.theme?.colors?.background || "hsl(0 0% 100%)"};
15733
- ` : `
15734
- right: -5px;
15735
- border-left: 6px solid ${props.theme?.colors?.background || "hsl(0 0% 100%)"};
15736
- `}
15737
- }
15738
- `}
15739
-
15740
- @media (max-width: 768px) {
15741
- width: 300px;
15742
- }
15743
-
15744
- table,
15745
- tr,
15746
- td,
15747
- th {
15748
- margin: 0;
15749
- padding: 0;
15750
- font-size: 0.875rem;
15751
- color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
15752
- text-align: left;
15753
- }
15754
- td {
15755
- padding: 0.5rem 0;
15756
- }
15757
- tr:hover {
15758
- background-color: ${(props)=>props.theme?.colors?.muted || "hsl(210 40% 96%)"};
15759
- }
15760
- th {
15761
- font-weight: 500;
15762
- border-bottom: 1px solid ${(props)=>props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
15763
- padding-bottom: 0.5rem;
15764
- }
15599
+ const CodeBlockContainer = styled.div`
15600
+ box-sizing: border-box;
15601
+ border-radius: 0.375rem;
15602
+ overflow: hidden;
15603
+ font-family: monospace;
15604
+ font-size: 0.75rem;
15605
+ line-height: 1.4;
15606
+ max-height: 150px;
15607
+ overflow-y: auto;
15765
15608
  `;
15766
- const PopoverHeader = styled.div`
15609
+ const CodeBlockHeader = styled.div`
15610
+ padding: 0.5rem 0.75rem;
15767
15611
  display: flex;
15768
15612
  justify-content: space-between;
15769
15613
  align-items: center;
15770
- flex-direction: row;
15771
- padding: 0.75rem 1rem;
15772
- border-bottom: 1px solid ${(props)=>props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
15773
- background-color: ${(props)=>props.theme?.colors?.card || "hsl(0 0% 100%)"};
15774
- border-radius: 0.5rem 0.5rem 0 0;
15775
15614
  `;
15776
- const PopoverTitle = styled.div`
15777
- display: flex;
15778
- align-items: center;
15779
- gap: 0.5rem;
15780
- font-weight: 600;
15781
- font-size: 0.875rem;
15782
- color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
15615
+ const CodeBlockLanguage = styled.span`
15616
+ font-size: 0.625rem;
15617
+ font-weight: 500;
15618
+ text-transform: uppercase;
15619
+ letter-spacing: 0.05em;
15783
15620
  `;
15784
- const PopoverHeaderButtons = styled.div`
15785
- display: flex;
15786
- align-items: center;
15787
- gap: 0.5rem;
15788
- justify-content: flex-start;
15621
+ const CodeBlockContent = styled.pre`
15622
+ margin: 0;
15623
+ padding: 0.75rem;
15624
+ white-space: pre-wrap;
15625
+ word-break: break-word;
15626
+ overflow-x: auto;
15789
15627
  `;
15790
- const CloseButton = styled.button`
15628
+
15629
+ // Styled Components
15630
+ const TreeNodeContainer = styled.div``;
15631
+ const TreeNodeRow = styled.div`
15791
15632
  display: flex;
15792
15633
  align-items: center;
15793
- justify-content: center;
15794
- width: 24px;
15795
- height: 24px;
15796
- border: none;
15634
+ gap: 0.25rem;
15635
+ padding: 0.25rem 0.5rem;
15797
15636
  border-radius: 0.25rem;
15798
- background-color: transparent;
15799
- color: ${(props)=>props.theme?.colors?.mutedForeground || "hsl(215.4 16.3% 46.9%)"};
15800
- cursor: pointer;
15801
- transition: all 0.2s ease-in-out;
15637
+ cursor: ${(props)=>props.isExpandable ? "pointer" : "default"};
15638
+ transition: background-color 0.15s ease-in-out;
15802
15639
 
15803
15640
  &:hover {
15804
- background-color: ${(props)=>props.theme?.colors?.muted || "hsl(210 40% 96%)"};
15805
- color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
15806
- }
15807
-
15808
- &:focus {
15809
- outline: 2px solid ${(props)=>props.theme?.colors?.primary || "hsl(221.2 83.2% 53.3%)"};
15810
- outline-offset: 2px;
15641
+ background-color: ${(props)=>props.isExpandable ? props.themeColors.muted : "transparent"};
15811
15642
  }
15812
15643
  `;
15813
- const PopoverBody = styled.div`
15814
- max-height: 500px;
15815
- overflow-y: auto;
15816
- padding: 1rem;
15644
+ const IconContainer = styled.div`
15645
+ width: 0.5rem;
15646
+ height: 0.5rem;
15647
+ flex-shrink: 0;
15817
15648
  display: flex;
15818
- flex-direction: column;
15819
- gap: 1rem;
15649
+ align-items: center;
15650
+ justify-content: center;
15651
+ color: ${(props)=>props.themeColors.mutedForeground};
15820
15652
  `;
15821
- const Section = styled.div`
15822
- display: flex;
15823
- flex-direction: column;
15824
- gap: 0.75rem;
15653
+ const Label$1 = styled.span`
15654
+ font-weight: 500;
15655
+ color: ${(props)=>props.themeColors.foreground};
15656
+ font-size: 0.75rem;
15825
15657
  `;
15826
- const InfoGrid = styled.div`
15827
- display: grid;
15828
- grid-template-columns: 1fr 1fr;
15829
- gap: 0.75rem;
15658
+ const Value$1 = styled.span`
15659
+ font-size: 0.75rem;
15660
+ color: ${(props)=>props.themeColors.primary};
15830
15661
  `;
15831
- const InfoItem = styled.div`
15832
- display: flex;
15833
- flex-direction: column;
15834
- gap: 0.25rem;
15662
+ const EmptyIndicator = styled.span`
15663
+ font-size: 0.75rem;
15664
+ color: ${(props)=>props.themeColors.mutedForeground};
15835
15665
  `;
15836
- const InfoLabel = styled.span`
15666
+ const ChildrenContainer = styled.div`
15667
+ margin-left: 0.5rem;
15668
+ `;
15669
+ const TreeContainer = styled.div`
15670
+ width: 100%;
15671
+ box-sizing: border-box;
15672
+ background-color: ${(props)=>props.themeColors.muted};
15673
+ border-radius: 0.5rem;
15674
+ border: 1px solid ${(props)=>props.themeColors.border};
15675
+ overflow: hidden;
15676
+ `;
15677
+ const TreeScrollContainer = styled.div`
15678
+ width: 100%;
15679
+ max-height: 16rem;
15680
+ overflow-y: auto;
15681
+ padding: 0.5rem;
15682
+ `;
15683
+ const NoDataMessage = styled.div`
15684
+ width: 100%;
15685
+ padding: 1rem;
15686
+ text-align: center;
15687
+ color: ${(props)=>props.themeColors.mutedForeground};
15688
+ font-size: 0.875rem;
15689
+ background-color: ${(props)=>props.themeColors.muted};
15690
+ border-radius: 0.5rem;
15691
+ border: 1px solid ${(props)=>props.themeColors.border};
15692
+ `;
15693
+ const SimpleValueContainer = styled.div`
15694
+ width: 100%;
15695
+ padding: 0.5rem;
15696
+ background-color: ${(props)=>props.themeColors.muted};
15697
+ border-radius: 0.5rem;
15698
+ border: 1px solid ${(props)=>props.themeColors.border};
15699
+ font-size: 0.75rem;
15700
+ color: ${(props)=>props.themeColors.foreground};
15701
+ word-break: break-all;
15702
+ `;
15703
+ styled.div`
15704
+ width: 100%;
15705
+ padding: 1rem;
15706
+ text-align: center;
15707
+ color: ${(props)=>props.themeColors.mutedForeground};
15837
15708
  font-size: 0.875rem;
15709
+ background-color: ${(props)=>props.themeColors.muted};
15710
+ border-radius: 0.5rem;
15711
+ border: 1px solid ${(props)=>props.themeColors.border};
15712
+ margin-bottom: 0.5rem;
15713
+ `;
15714
+ const SimpleValueLabel = styled.span`
15838
15715
  font-weight: 500;
15839
- color: ${(props)=>props.theme?.colors?.mutedForeground || "hsl(215.4 16.3% 46.9%)"};
15716
+ color: ${(props)=>props.themeColors.cardForeground};
15717
+ font-size: 0.875rem;
15840
15718
  `;
15841
- const InfoValue = styled.span`
15842
- font-size: 0.875rem;
15843
- color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
15844
- word-break: break-word;
15845
- `;
15846
- const NodeIcon$3 = styled.div`
15847
- font-size: 1.25rem;
15848
- display: flex;
15849
- align-items: center;
15850
- justify-content: center;
15851
- color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
15852
- `;
15853
-
15854
- const ExpandableTextarea = ({ label, content, isExpanded, onToggle })=>{
15855
- const { theme } = useTheme();
15856
- const themeColors = theme?.colors || {
15857
- muted: "hsl(210 40% 96%)",
15858
- mutedForeground: "hsl(215.4 16.3% 46.9%)",
15859
- border: "hsl(214.3 31.8% 91.4%)",
15860
- foreground: "hsl(222.2 84% 4.9%)"
15861
- };
15862
- const displayContent = isExpanded ? content : content?.slice(0, 100) + (content?.length > 100 ? "..." : "");
15863
- return /*#__PURE__*/ React.createElement(ExpandableSection, null, /*#__PURE__*/ React.createElement(ExpandableHeader, {
15864
- onClick: (e)=>{
15865
- e.stopPropagation();
15866
- onToggle(e);
15867
- },
15868
- onMouseEnter: (e)=>{
15869
- e.currentTarget.style.backgroundColor = themeColors.muted;
15870
- },
15871
- onMouseLeave: (e)=>{
15872
- e.currentTarget.style.backgroundColor = "transparent";
15873
- }
15874
- }, /*#__PURE__*/ React.createElement(ExpandableLabel, null, label), /*#__PURE__*/ React.createElement(ChevronIcon, null, isExpanded ? /*#__PURE__*/ React.createElement(ChevronDown, {
15875
- style: {
15876
- width: "12px",
15877
- height: "12px",
15878
- color: themeColors.mutedForeground
15879
- }
15880
- }) : /*#__PURE__*/ React.createElement(ChevronRight, {
15881
- style: {
15882
- width: "12px",
15883
- height: "12px",
15884
- color: themeColors.mutedForeground
15885
- }
15886
- }))), /*#__PURE__*/ React.createElement(ExpandableTextareaElement, {
15887
- onClick: (e)=>{
15888
- e.stopPropagation();
15889
- },
15890
- value: displayContent || "",
15891
- readOnly: true,
15892
- rows: isExpanded ? Math.max(3, Math.max(content?.split("\n").length || 0, Math.ceil((content?.length || 0) / 60))) : 2,
15893
- style: {
15894
- border: `1px solid ${themeColors.border}`,
15895
- backgroundColor: themeColors.muted,
15896
- color: themeColors.foreground
15897
- }
15898
- }));
15899
- };
15900
- // Styled components
15901
- const ExpandableSection = styled.div`
15902
- width: 100%;
15903
- `;
15904
- const ExpandableHeader = styled.div`
15905
- display: flex;
15906
- justify-content: space-between;
15907
- align-items: center;
15908
- padding: 0.25rem 0;
15909
- cursor: pointer;
15910
- user-select: none;
15911
- border-radius: 0.25rem;
15912
- padding-left: 0.25rem;
15913
- padding-right: 0.25rem;
15914
-
15915
- &:hover {
15916
- background-color: transparent;
15917
- }
15918
- `;
15919
- const ExpandableLabel = styled.span`
15920
- font-size: 0.75rem;
15921
- font-weight: 500;
15922
- color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
15923
- `;
15924
- const ExpandableTextareaElement = styled.textarea`
15925
- box-sizing: border-box;
15926
- width: 100%;
15927
- border-radius: 0.25rem;
15928
- padding: 0.5rem;
15929
- resize: none;
15930
- min-height: 40px;
15931
- font-family: inherit;
15932
-
15933
- &:focus {
15934
- outline: none;
15935
- border-color: ${(props)=>props.theme?.colors?.primary || "hsl(221.2 83.2% 53.3%)"};
15936
- box-shadow: 0 0 0 1px ${(props)=>props.theme?.colors?.primary || "hsl(221.2 83.2% 53.3%)"};
15937
- }
15938
-
15939
- transition: all 0.2s ease-in-out;
15940
- `;
15941
- const ChevronIcon = styled.div`
15942
- transition: transform 0.2s ease-in-out;
15943
- `;
15944
-
15945
- const CodeBlock = ({ content, language = "text", showHeader = false })=>{
15946
- const { theme } = useTheme();
15947
- const themeColors = theme?.colors || {
15948
- muted: "hsl(210 40% 96%)",
15949
- mutedForeground: "hsl(215.4 16.3% 46.9%)",
15950
- border: "hsl(214.3 31.8% 91.4%)",
15951
- foreground: "hsl(222.2 84% 4.9%)",
15952
- background: "hsl(0 0% 100%)"
15953
- };
15954
- return /*#__PURE__*/ React.createElement(CodeBlockContainer, {
15955
- style: {
15956
- width: "100%",
15957
- border: `1px solid ${themeColors.border}`,
15958
- backgroundColor: themeColors.muted,
15959
- color: themeColors.foreground
15960
- }
15961
- }, showHeader && /*#__PURE__*/ React.createElement(CodeBlockHeader, {
15962
- style: {
15963
- borderBottom: `1px solid ${themeColors.border}`,
15964
- backgroundColor: themeColors.background
15965
- }
15966
- }, /*#__PURE__*/ React.createElement(CodeBlockLanguage, {
15967
- style: {
15968
- color: themeColors.mutedForeground
15969
- }
15970
- }, language)), /*#__PURE__*/ React.createElement(CodeBlockContent, {
15971
- style: {
15972
- color: themeColors.foreground
15973
- }
15974
- }, content));
15975
- };
15976
- const CodeBlockContainer = styled.div`
15977
- box-sizing: border-box;
15978
- border-radius: 0.375rem;
15979
- overflow: hidden;
15980
- font-family: monospace;
15981
- font-size: 0.75rem;
15982
- line-height: 1.4;
15983
- max-height: 150px;
15984
- overflow-y: auto;
15985
- `;
15986
- const CodeBlockHeader = styled.div`
15987
- padding: 0.5rem 0.75rem;
15988
- display: flex;
15989
- justify-content: space-between;
15990
- align-items: center;
15991
- `;
15992
- const CodeBlockLanguage = styled.span`
15993
- font-size: 0.625rem;
15994
- font-weight: 500;
15995
- text-transform: uppercase;
15996
- letter-spacing: 0.05em;
15997
- `;
15998
- const CodeBlockContent = styled.pre`
15999
- margin: 0;
16000
- padding: 0.75rem;
16001
- white-space: pre-wrap;
16002
- word-break: break-word;
16003
- overflow-x: auto;
16004
- `;
16005
-
16006
- // Styled Components
16007
- const TreeNodeContainer = styled.div`
16008
- user-select: none;
16009
- `;
16010
- const TreeNodeRow = styled.div`
16011
- display: flex;
16012
- align-items: center;
16013
- gap: 0.25rem;
16014
- padding: 0.25rem 0.5rem;
16015
- border-radius: 0.25rem;
16016
- cursor: ${(props)=>props.isExpandable ? "pointer" : "default"};
16017
- transition: background-color 0.15s ease-in-out;
16018
-
16019
- &:hover {
16020
- background-color: ${(props)=>props.isExpandable ? props.themeColors.muted : "transparent"};
16021
- }
16022
- `;
16023
- const IconContainer = styled.div`
16024
- width: 0.5rem;
16025
- height: 0.5rem;
16026
- flex-shrink: 0;
16027
- display: flex;
16028
- align-items: center;
16029
- justify-content: center;
16030
- color: ${(props)=>props.themeColors.mutedForeground};
16031
- `;
16032
- const Label$1 = styled.span`
16033
- font-weight: 500;
16034
- color: ${(props)=>props.themeColors.foreground};
16035
- font-size: 0.75rem;
16036
- `;
16037
- const Value$1 = styled.span`
16038
- font-size: 0.75rem;
16039
- color: ${(props)=>props.themeColors.primary};
16040
- `;
16041
- const EmptyIndicator = styled.span`
16042
- font-size: 0.75rem;
16043
- color: ${(props)=>props.themeColors.mutedForeground};
16044
- `;
16045
- const ChildrenContainer = styled.div`
16046
- margin-left: 0.5rem;
16047
- `;
16048
- const TreeContainer = styled.div`
16049
- width: 100%;
16050
- box-sizing: border-box;
16051
- background-color: ${(props)=>props.themeColors.muted};
16052
- border-radius: 0.5rem;
16053
- border: 1px solid ${(props)=>props.themeColors.border};
16054
- overflow: hidden;
16055
- `;
16056
- const TreeScrollContainer = styled.div`
16057
- width: 100%;
16058
- max-height: 16rem;
16059
- overflow-y: auto;
16060
- padding: 0.5rem;
16061
- `;
16062
- const NoDataMessage = styled.div`
16063
- width: 100%;
16064
- padding: 1rem;
16065
- text-align: center;
16066
- color: ${(props)=>props.themeColors.mutedForeground};
16067
- font-size: 0.875rem;
16068
- background-color: ${(props)=>props.themeColors.muted};
16069
- border-radius: 0.5rem;
16070
- border: 1px solid ${(props)=>props.themeColors.border};
16071
- `;
16072
- const SimpleValueContainer = styled.div`
16073
- width: 100%;
16074
- padding: 0.5rem;
16075
- background-color: ${(props)=>props.themeColors.muted};
16076
- border-radius: 0.5rem;
16077
- border: 1px solid ${(props)=>props.themeColors.border};
16078
- font-size: 0.75rem;
16079
- color: ${(props)=>props.themeColors.foreground};
16080
- word-break: break-all;
16081
- `;
16082
- styled.div`
16083
- width: 100%;
16084
- padding: 1rem;
16085
- text-align: center;
16086
- color: ${(props)=>props.themeColors.mutedForeground};
16087
- font-size: 0.875rem;
16088
- background-color: ${(props)=>props.themeColors.muted};
16089
- border-radius: 0.5rem;
16090
- border: 1px solid ${(props)=>props.themeColors.border};
16091
- margin-bottom: 0.5rem;
16092
- `;
16093
- const SimpleValueLabel = styled.span`
16094
- font-weight: 500;
16095
- color: ${(props)=>props.themeColors.cardForeground};
16096
- font-size: 0.875rem;
16097
- `;
16098
- const SimpleValueText = styled.span`
16099
- color: ${(props)=>props.themeColors.foreground};
15719
+ const SimpleValueText = styled.span`
15720
+ color: ${(props)=>props.themeColors.foreground};
16100
15721
  font-size: 0.875rem;
16101
15722
  `;
16102
15723
  const EmptyStateContainer = styled.div`
@@ -16241,7 +15862,8 @@ const JsonTreeViewer = ({ data, maxDepth = 4, initialExpanded = false, expanded
16241
15862
  }
16242
15863
  return /*#__PURE__*/ React.createElement(TreeContainer, {
16243
15864
  themeColors: themeColors,
16244
- className: className
15865
+ className: className,
15866
+ onClick: (e)=>e.stopPropagation()
16245
15867
  }, /*#__PURE__*/ React.createElement(TreeScrollContainer, null, (()=>{
16246
15868
  const entries = sortObjectEntries(data, priorityKeys, excludeKeys);
16247
15869
  if (entries.length === 0) {
@@ -16635,97 +16257,671 @@ const InputArrayRenderer = ({ input })=>{
16635
16257
  };
16636
16258
  return /*#__PURE__*/ React.createElement(InputArrayContainer, null, /*#__PURE__*/ React.createElement(InputArrayHeader, null, /*#__PURE__*/ React.createElement("h3", null, "Input"), /*#__PURE__*/ React.createElement("span", {
16637
16259
  style: {
16638
- display: "flex",
16639
- alignItems: "center",
16640
- gap: "0.25rem"
16260
+ display: "flex",
16261
+ alignItems: "center",
16262
+ gap: "0.25rem"
16263
+ }
16264
+ }, /*#__PURE__*/ React.createElement(MessageSquare, {
16265
+ size: 12
16266
+ }), input.length)), /*#__PURE__*/ React.createElement(InputArrayScrollableContent, null, input.map((item, index)=>/*#__PURE__*/ React.createElement(InputItem, {
16267
+ key: index
16268
+ }, /*#__PURE__*/ React.createElement(InputItemHeader, null, /*#__PURE__*/ React.createElement(InputItemLabel, null, getRoleEmoji(item.role), " ", getRoleDisplayName(item.role))), /*#__PURE__*/ React.createElement(InputItemTextarea, {
16269
+ onClick: (e)=>{
16270
+ e.stopPropagation();
16271
+ },
16272
+ value: renderContent(item.content) || "",
16273
+ readOnly: true,
16274
+ style: {
16275
+ border: `1px solid ${themeColors.border}`,
16276
+ backgroundColor: themeColors.muted,
16277
+ color: themeColors.foreground
16278
+ }
16279
+ })))));
16280
+ };
16281
+ // Styled components
16282
+ const InputArrayContainer = styled.div`
16283
+ width: 100%;
16284
+ display: flex;
16285
+ flex-direction: column;
16286
+ gap: 0.5rem;
16287
+ `;
16288
+ const InputArrayScrollableContent = styled.div`
16289
+ width: 100%;
16290
+ display: flex;
16291
+ flex-direction: column;
16292
+ padding-bottom: 0.5rem;
16293
+ gap: 0.5rem;
16294
+ max-height: 200px;
16295
+ overflow-y: auto;
16296
+ `;
16297
+ const InputArrayHeader = styled.div`
16298
+ display: flex;
16299
+ align-items: center;
16300
+ justify-content: space-between;
16301
+ font-weight: 500;
16302
+ font-size: 0.75rem;
16303
+ color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
16304
+
16305
+ & h3 {
16306
+ margin: 0;
16307
+ padding: 0;
16308
+ font-size: 0.75rem;
16309
+ font-weight: 500;
16310
+ color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
16311
+ }
16312
+
16313
+ & span {
16314
+ font-size: 0.75rem;
16315
+ font-weight: 500;
16316
+ opacity: 0.5;
16317
+ color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
16318
+ }
16319
+ `;
16320
+ const InputItem = styled.div`
16321
+ width: 100%;
16322
+ display: flex;
16323
+ flex-direction: column;
16324
+ gap: 0.25rem;
16325
+ `;
16326
+ const InputItemHeader = styled.div`
16327
+ display: flex;
16328
+ align-items: center;
16329
+ gap: 0.25rem;
16330
+ `;
16331
+ const InputItemLabel = styled.span`
16332
+ font-weight: 600;
16333
+ font-size: 0.75rem;
16334
+ color: ${(props)=>props.theme?.colors?.mutedForeground || "hsl(215.4 16.3% 46.9%)"};
16335
+ `;
16336
+ const InputItemTextarea = styled(index$1)`
16337
+ box-sizing: border-box;
16338
+ width: 100%;
16339
+ border-radius: 0.25rem;
16340
+ padding: 0.5rem;
16341
+ resize: none;
16342
+ font-family: inherit;
16343
+ font-size: 0.75rem;
16344
+ &:focus {
16345
+ outline: none;
16346
+ border-color: ${(props)=>props.theme?.colors?.primary || "hsl(221.2 83.2% 53.3%)"};
16347
+ box-shadow: 0 0 0 1px ${(props)=>props.theme?.colors?.primary || "hsl(221.2 83.2% 53.3%)"};
16348
+ }
16349
+
16350
+ transition: all 0.2s ease-in-out;
16351
+ `;
16352
+
16353
+ const DEFAULT_COUNTUP_DURATION = 0.6;
16354
+ // Helper component for animating currency values
16355
+ const CountUpCurrency = ({ value, prefix = "", suffix = "" })=>{
16356
+ return /*#__PURE__*/ React.createElement(CountUp, {
16357
+ end: value,
16358
+ duration: DEFAULT_COUNTUP_DURATION,
16359
+ separator: ",",
16360
+ decimals: 2,
16361
+ decimal: ".",
16362
+ prefix: prefix,
16363
+ useEasing: true,
16364
+ suffix: suffix
16365
+ });
16366
+ };
16367
+ // Helper component for animating latency values
16368
+ const CountUpLatency = ({ value })=>{
16369
+ if (value < 1) {
16370
+ // Show as milliseconds
16371
+ return /*#__PURE__*/ React.createElement(CountUp, {
16372
+ end: Math.round(value * 1000),
16373
+ duration: DEFAULT_COUNTUP_DURATION,
16374
+ separator: ",",
16375
+ useEasing: true,
16376
+ suffix: "ms"
16377
+ });
16378
+ } else if (value < 60) {
16379
+ // Show as seconds with 1 decimal place
16380
+ return /*#__PURE__*/ React.createElement(CountUp, {
16381
+ end: value,
16382
+ duration: DEFAULT_COUNTUP_DURATION,
16383
+ decimals: 1,
16384
+ useEasing: true,
16385
+ suffix: "s"
16386
+ });
16387
+ } else {
16388
+ // Show as minutes and seconds (animate just the total seconds for simplicity)
16389
+ return /*#__PURE__*/ React.createElement(CountUp, {
16390
+ end: value,
16391
+ duration: DEFAULT_COUNTUP_DURATION,
16392
+ decimals: 1,
16393
+ useEasing: true,
16394
+ suffix: "s"
16395
+ });
16396
+ }
16397
+ };
16398
+ // Helper function to get node icon
16399
+ const getNodeIcon$1 = (nodeType, modelProvider)=>{
16400
+ nodeType = nodeType.toLowerCase();
16401
+ if (nodeType === "tool") {
16402
+ return "🔧";
16403
+ }
16404
+ if (nodeType === "coordinator") {
16405
+ return "🎯";
16406
+ }
16407
+ if (nodeType === "agent") {
16408
+ if (modelProvider === "OpenAI") {
16409
+ return /*#__PURE__*/ React.createElement(OpenAIIcon, null);
16410
+ }
16411
+ if (modelProvider === "Anthropic") {
16412
+ return /*#__PURE__*/ React.createElement(AnthropicIcon, null);
16413
+ }
16414
+ if (modelProvider === "Google" || modelProvider === "Vertex_AI") {
16415
+ return /*#__PURE__*/ React.createElement(GoogleIcon, null);
16416
+ }
16417
+ }
16418
+ return "🤖";
16419
+ };
16420
+ const NodeDetailsPopover = ({ isVisible, onClose, nodeData, triggerRef })=>{
16421
+ const [position, setPosition] = React.useState({
16422
+ top: 0,
16423
+ left: 0,
16424
+ arrowPosition: "right"
16425
+ });
16426
+ const [selectedRowIndex, setSelectedRowIndex] = React.useState(null);
16427
+ const [selectedLlmDetails, setSelectedLlmDetails] = React.useState(null);
16428
+ // Default to last row (total/aggregate) when popover opens (only on first open)
16429
+ React.useEffect(()=>{
16430
+ if (isVisible && nodeData.details?.internals?.llm_details && selectedRowIndex === null) {
16431
+ const llmDetailsLength = nodeData.details.internals.llm_details.length;
16432
+ setSelectedRowIndex(llmDetailsLength); // Last index + 1 for total row
16433
+ setSelectedLlmDetails(nodeData.details.internals.llm_details[llmDetailsLength]);
16434
+ }
16435
+ }, [
16436
+ isVisible,
16437
+ nodeData.details?.internals?.llm_details,
16438
+ selectedRowIndex
16439
+ ]);
16440
+ const handleShowModelDetails = (details, index)=>{
16441
+ setSelectedRowIndex(index);
16442
+ setSelectedLlmDetails(details);
16443
+ };
16444
+ const handleShowAggregateDetails = ()=>{
16445
+ if (nodeData.details?.internals?.llm_details) {
16446
+ setSelectedRowIndex(nodeData.details.internals.llm_details.length);
16447
+ setSelectedLlmDetails(nodeData.details.internals.llm_details[nodeData.details.internals.llm_details.length]);
16448
+ }
16449
+ };
16450
+ // Calculate popover position based on trigger element
16451
+ React.useEffect(()=>{
16452
+ if (isVisible && triggerRef.current) {
16453
+ const rect = triggerRef.current.getBoundingClientRect();
16454
+ const viewportWidth = window.innerWidth;
16455
+ const viewportHeight = window.innerHeight;
16456
+ const popoverWidth = 400; // Match the width from styled component
16457
+ const popoverHeight = 600; // Approximate max height
16458
+ const gap = 12; // Gap between node and popover
16459
+ // Check if the rect is valid (has non-zero dimensions and is in viewport)
16460
+ const isValidRect = rect.width > 0 && rect.height > 0 && rect.top >= 0 && rect.left >= 0;
16461
+ if (isValidRect) {
16462
+ // Normal positioning logic for ReactFlow
16463
+ let left = rect.right + gap;
16464
+ let top = rect.top;
16465
+ let arrowPosition = "right"; // Arrow points right (popover is to the right)
16466
+ // If popover would go off-screen, position it to the left of the node
16467
+ if (left + popoverWidth > viewportWidth) {
16468
+ left = rect.left - popoverWidth - gap;
16469
+ arrowPosition = "left"; // Arrow points left (popover is to the left)
16470
+ }
16471
+ // Ensure popover doesn't go off the top or bottom of the viewport
16472
+ if (top < 0) {
16473
+ top = 20; // Small margin from top
16474
+ } else if (top + popoverHeight > viewportHeight) {
16475
+ top = viewportHeight - popoverHeight - 20; // Small margin from bottom
16476
+ }
16477
+ setPosition({
16478
+ top,
16479
+ left,
16480
+ arrowPosition
16481
+ });
16482
+ } else {
16483
+ // Fallback positioning for isolated environments (like Storybook)
16484
+ // Center the popover in the viewport
16485
+ const centerLeft = Math.max(20, (viewportWidth - popoverWidth) / 2);
16486
+ const centerTop = Math.max(20, (viewportHeight - popoverHeight) / 2);
16487
+ setPosition({
16488
+ top: centerTop,
16489
+ left: centerLeft,
16490
+ arrowPosition: "none" // No arrow in fallback mode
16491
+ });
16492
+ }
16493
+ }
16494
+ }, [
16495
+ isVisible,
16496
+ triggerRef
16497
+ ]);
16498
+ // Handle ESC key to close popover
16499
+ React.useEffect(()=>{
16500
+ const handleEscKey = (event)=>{
16501
+ if (event.key === "Escape") {
16502
+ onClose();
16503
+ }
16504
+ };
16505
+ if (isVisible) {
16506
+ document.addEventListener("keydown", handleEscKey);
16507
+ return ()=>document.removeEventListener("keydown", handleEscKey);
16508
+ }
16509
+ }, [
16510
+ isVisible,
16511
+ onClose
16512
+ ]);
16513
+ React.useEffect(()=>{
16514
+ // Reset selected llm details and row index when popover is closed and reopened
16515
+ setSelectedLlmDetails(null);
16516
+ setSelectedRowIndex(nodeData?.details?.internals?.llm_details?.length || null);
16517
+ }, [
16518
+ nodeData?.details?.internals?.llm_details?.length
16519
+ ]);
16520
+ // Handle click outside to close popover
16521
+ React.useEffect(()=>{
16522
+ const handleClickOutside = (event)=>{
16523
+ if (isVisible && triggerRef.current && !triggerRef.current.contains(event.target) && !event.target.closest("[data-popover-content]")) {
16524
+ onClose();
16525
+ }
16526
+ };
16527
+ if (isVisible) {
16528
+ document.addEventListener("mousedown", handleClickOutside);
16529
+ return ()=>document.removeEventListener("mousedown", handleClickOutside);
16530
+ }
16531
+ }, [
16532
+ isVisible,
16533
+ onClose,
16534
+ triggerRef
16535
+ ]);
16536
+ if (!isVisible) return null;
16537
+ const llOverviewDetails = getOverviewLlmDetails(nodeData.details?.internals?.llm_details || []);
16538
+ const totalCost = sumTotalCost(nodeData.details?.internals?.llm_details || []);
16539
+ const totalInputTokens = sumTotalInputTokens(nodeData.details?.internals?.llm_details || []);
16540
+ const totalOutputTokens = sumTotalOutputTokens(nodeData.details?.internals?.llm_details || []);
16541
+ const totalLatency = sumTotalLatency(nodeData.details?.internals?.llm_details || []);
16542
+ const popoverContent = /*#__PURE__*/ React.createElement(PopoverPortal, {
16543
+ style: {
16544
+ top: position.top,
16545
+ left: position.left
16546
+ }
16547
+ }, /*#__PURE__*/ React.createElement(PopoverContent, {
16548
+ "data-popover-content": true,
16549
+ $arrowPosition: position.arrowPosition
16550
+ }, /*#__PURE__*/ React.createElement(PopoverHeader, null, /*#__PURE__*/ React.createElement(PopoverTitle, null, /*#__PURE__*/ React.createElement(NodeIcon$3, null, getNodeIcon$1(nodeData.nodeType || "Agent", llOverviewDetails?.model_provider)), /*#__PURE__*/ React.createElement("span", null, nodeData.label, " Details")), /*#__PURE__*/ React.createElement(PopoverHeaderButtons, null, /*#__PURE__*/ React.createElement(CloseButton, {
16551
+ onClick: onClose
16552
+ }, /*#__PURE__*/ React.createElement(X, {
16553
+ size: 16
16554
+ })))), /*#__PURE__*/ React.createElement(PopoverBody, null, llOverviewDetails && /*#__PURE__*/ React.createElement(Section, null, /*#__PURE__*/ React.createElement(InfoGrid, null, (()=>{
16555
+ const llmDetails = nodeData.details?.internals?.llm_details || [];
16556
+ const isAggregateSelected = selectedRowIndex === llmDetails.length;
16557
+ const selectedDetails = isAggregateSelected ? null // Use aggregate values
16558
+ : llmDetails[selectedRowIndex || 0];
16559
+ return /*#__PURE__*/ React.createElement(React.Fragment, null, /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, "Model"), /*#__PURE__*/ React.createElement(InfoValue, null, isAggregateSelected ? llOverviewDetails.model_name : selectedDetails?.model_name || "N/A")), /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, "Provider"), /*#__PURE__*/ React.createElement(InfoValue, null, isAggregateSelected ? llOverviewDetails.model_provider : selectedDetails?.model_provider || "N/A")), /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, isAggregateSelected ? "Total" : "", " Latency"), /*#__PURE__*/ React.createElement(InfoValue, null, isAggregateSelected ? totalLatency ? /*#__PURE__*/ React.createElement(CountUpLatency, {
16560
+ value: totalLatency
16561
+ }) : "N/A" : selectedDetails?.latency ? /*#__PURE__*/ React.createElement(CountUpLatency, {
16562
+ value: selectedDetails.latency
16563
+ }) : "N/A")), /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, "Input Tokens"), /*#__PURE__*/ React.createElement(InfoValue, null, isAggregateSelected ? totalInputTokens ? /*#__PURE__*/ React.createElement(CountUp, {
16564
+ end: totalInputTokens,
16565
+ duration: DEFAULT_COUNTUP_DURATION,
16566
+ separator: ",",
16567
+ useEasing: true
16568
+ }) : "N/A" : selectedDetails?.input_tokens ? /*#__PURE__*/ React.createElement(CountUp, {
16569
+ end: selectedDetails.input_tokens,
16570
+ duration: DEFAULT_COUNTUP_DURATION,
16571
+ separator: ",",
16572
+ useEasing: true
16573
+ }) : "N/A")), /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, "Output Tokens"), /*#__PURE__*/ React.createElement(InfoValue, null, isAggregateSelected ? totalOutputTokens ? /*#__PURE__*/ React.createElement(CountUp, {
16574
+ end: totalOutputTokens,
16575
+ duration: DEFAULT_COUNTUP_DURATION,
16576
+ separator: ",",
16577
+ useEasing: true
16578
+ }) : "N/A" : selectedDetails?.output_tokens ? /*#__PURE__*/ React.createElement(CountUp, {
16579
+ end: selectedDetails.output_tokens,
16580
+ duration: DEFAULT_COUNTUP_DURATION,
16581
+ separator: ",",
16582
+ useEasing: true
16583
+ }) : "N/A")), /*#__PURE__*/ React.createElement(InfoItem, null, /*#__PURE__*/ React.createElement(InfoLabel, null, isAggregateSelected ? "Total" : "", " Cost"), /*#__PURE__*/ React.createElement(InfoValue, null, isAggregateSelected ? totalCost ? /*#__PURE__*/ React.createElement("span", null, "~", /*#__PURE__*/ React.createElement(CountUpCurrency, {
16584
+ value: totalCost,
16585
+ prefix: "$",
16586
+ suffix: " USD"
16587
+ })) : "N/A" : selectedDetails?.total_cost ? /*#__PURE__*/ React.createElement(CountUpCurrency, {
16588
+ value: selectedDetails.total_cost,
16589
+ prefix: "$",
16590
+ suffix: " USD"
16591
+ }) : "N/A")));
16592
+ })())), nodeData.details?.internals?.llm_details.length > 1 && /*#__PURE__*/ React.createElement(Section, null, /*#__PURE__*/ React.createElement("table", null, /*#__PURE__*/ React.createElement("thead", null, /*#__PURE__*/ React.createElement("tr", null, /*#__PURE__*/ React.createElement("th", {
16593
+ style: {
16594
+ textAlign: "center"
16595
+ }
16596
+ }, "#"), /*#__PURE__*/ React.createElement("th", {
16597
+ style: {
16598
+ textAlign: "right"
16599
+ }
16600
+ }, "Input Tokens"), /*#__PURE__*/ React.createElement("th", {
16601
+ style: {
16602
+ textAlign: "right"
16603
+ }
16604
+ }, "Output Tokens"), /*#__PURE__*/ React.createElement("th", {
16605
+ style: {
16606
+ textAlign: "right"
16607
+ }
16608
+ }, "Total Cost"), /*#__PURE__*/ React.createElement("th", {
16609
+ style: {
16610
+ textAlign: "right"
16611
+ }
16612
+ }, "Latency"))), /*#__PURE__*/ React.createElement("tbody", null, nodeData.details?.internals?.llm_details.map((details, index)=>/*#__PURE__*/ React.createElement("tr", {
16613
+ key: index,
16614
+ onClick: ()=>handleShowModelDetails(details, index),
16615
+ className: selectedRowIndex === index ? "selected-row" : ""
16616
+ }, /*#__PURE__*/ React.createElement("td", {
16617
+ style: {
16618
+ textAlign: "center"
16619
+ }
16620
+ }, index + 1), /*#__PURE__*/ React.createElement("td", {
16621
+ style: {
16622
+ textAlign: "right"
16623
+ }
16624
+ }, details.input_tokens ? /*#__PURE__*/ React.createElement(CountUp, {
16625
+ end: details.input_tokens,
16626
+ duration: DEFAULT_COUNTUP_DURATION,
16627
+ separator: ",",
16628
+ useEasing: true
16629
+ }) : "N/A"), /*#__PURE__*/ React.createElement("td", {
16630
+ style: {
16631
+ textAlign: "right"
16632
+ }
16633
+ }, details.output_tokens ? /*#__PURE__*/ React.createElement(CountUp, {
16634
+ end: details.output_tokens,
16635
+ duration: DEFAULT_COUNTUP_DURATION,
16636
+ separator: ",",
16637
+ useEasing: true
16638
+ }) : "N/A"), /*#__PURE__*/ React.createElement("td", {
16639
+ style: {
16640
+ textAlign: "right"
16641
+ }
16642
+ }, details.total_cost ? /*#__PURE__*/ React.createElement(CountUpCurrency, {
16643
+ value: details.total_cost,
16644
+ prefix: "$"
16645
+ }) : "N/A"), /*#__PURE__*/ React.createElement("td", {
16646
+ style: {
16647
+ textAlign: "right"
16648
+ }
16649
+ }, details.latency ? /*#__PURE__*/ React.createElement(CountUpLatency, {
16650
+ value: details.latency
16651
+ }) : "N/A"))), /*#__PURE__*/ React.createElement("tr", {
16652
+ key: "total",
16653
+ className: `total-row ${selectedRowIndex === nodeData.details?.internals?.llm_details.length ? "selected-row" : ""}`,
16654
+ onClick: handleShowAggregateDetails
16655
+ }, /*#__PURE__*/ React.createElement("td", {
16656
+ style: {
16657
+ textAlign: "right"
16658
+ }
16659
+ }, " "), /*#__PURE__*/ React.createElement("td", {
16660
+ style: {
16661
+ textAlign: "right"
16662
+ }
16663
+ }, totalInputTokens ? /*#__PURE__*/ React.createElement(CountUp, {
16664
+ end: totalInputTokens,
16665
+ duration: DEFAULT_COUNTUP_DURATION,
16666
+ separator: ",",
16667
+ useEasing: true
16668
+ }) : "N/A"), /*#__PURE__*/ React.createElement("td", {
16669
+ style: {
16670
+ textAlign: "right"
16671
+ }
16672
+ }, totalOutputTokens ? /*#__PURE__*/ React.createElement(CountUp, {
16673
+ end: totalOutputTokens,
16674
+ duration: DEFAULT_COUNTUP_DURATION,
16675
+ separator: ",",
16676
+ useEasing: true
16677
+ }) : "N/A"), /*#__PURE__*/ React.createElement("td", {
16678
+ style: {
16679
+ textAlign: "right"
16680
+ }
16681
+ }, totalCost ? /*#__PURE__*/ React.createElement(CountUpCurrency, {
16682
+ value: totalCost,
16683
+ prefix: "$"
16684
+ }) : "N/A"), /*#__PURE__*/ React.createElement("td", {
16685
+ style: {
16686
+ textAlign: "right"
16641
16687
  }
16642
- }, /*#__PURE__*/ React.createElement(MessageSquare, {
16643
- size: 12
16644
- }), input.length)), /*#__PURE__*/ React.createElement(InputArrayScrollableContent, null, input.map((item, index)=>/*#__PURE__*/ React.createElement(InputItem, {
16645
- key: index
16646
- }, /*#__PURE__*/ React.createElement(InputItemHeader, null, /*#__PURE__*/ React.createElement(InputItemLabel, null, getRoleEmoji(item.role), " ", getRoleDisplayName(item.role))), /*#__PURE__*/ React.createElement(InputItemTextarea, {
16647
- onClick: (e)=>{
16648
- e.stopPropagation();
16649
- },
16650
- defaultValue: renderContent(item.content) || "",
16651
- readOnly: true,
16652
- style: {
16653
- border: `1px solid ${themeColors.border}`,
16654
- backgroundColor: themeColors.muted,
16655
- color: themeColors.foreground
16656
- }
16657
- })))));
16688
+ }, totalLatency ? /*#__PURE__*/ React.createElement(CountUpLatency, {
16689
+ value: totalLatency
16690
+ }) : "N/A")))), selectedLlmDetails ? /*#__PURE__*/ React.createElement(FadingSection, null, /*#__PURE__*/ React.createElement(InputArrayRenderer, {
16691
+ input: selectedLlmDetails.input || []
16692
+ }), /*#__PURE__*/ React.createElement(OutputRenderer, {
16693
+ data: selectedLlmDetails.output
16694
+ })) : null))));
16695
+ // Use React Portal to render outside of ReactFlow container
16696
+ return /*#__PURE__*/ ReactDOM.createPortal(popoverContent, document.body);
16658
16697
  };
16659
16698
  // Styled components
16660
- const InputArrayContainer = styled.div`
16661
- width: 100%;
16699
+ const PopoverPortal = styled.div`
16700
+ position: fixed;
16701
+ z-index: 99999;
16702
+ pointer-events: none;
16703
+ `;
16704
+ const PopoverContent = styled.div`
16705
+ width: 400px;
16706
+ max-height: 600px;
16707
+ background-color: ${(props)=>props.theme?.colors?.background || "hsl(0 0% 100%)"};
16708
+ border: 1px solid ${(props)=>props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
16709
+ border-radius: 0.5rem;
16710
+ box-shadow:
16711
+ 0 10px 15px -3px rgba(0, 0, 0, 0.1),
16712
+ 0 4px 6px -2px rgba(0, 0, 0, 0.05);
16713
+ z-index: 99999;
16714
+ pointer-events: auto;
16715
+ animation: popoverSlideIn 200ms ease-out;
16716
+
16717
+ @keyframes popoverSlideIn {
16718
+ from {
16719
+ transform: translateX(-10px);
16720
+ opacity: 0;
16721
+ }
16722
+ to {
16723
+ transform: translateX(0);
16724
+ opacity: 1;
16725
+ }
16726
+ }
16727
+
16728
+ /* Arrow pointing to the node - only show when not in fallback mode */
16729
+ ${(props)=>props.$arrowPosition !== "none" && `
16730
+ &::before {
16731
+ content: "";
16732
+ position: absolute;
16733
+ top: 20px;
16734
+ width: 0;
16735
+ height: 0;
16736
+ border-top: 6px solid transparent;
16737
+ border-bottom: 6px solid transparent;
16738
+ ${props.$arrowPosition === "right" ? `
16739
+ left: -6px;
16740
+ border-right: 6px solid ${props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
16741
+ ` : `
16742
+ right: -6px;
16743
+ border-left: 6px solid ${props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
16744
+ `}
16745
+ }
16746
+
16747
+ &::after {
16748
+ content: "";
16749
+ position: absolute;
16750
+ top: 20px;
16751
+ width: 0;
16752
+ height: 0;
16753
+ border-top: 6px solid transparent;
16754
+ border-bottom: 6px solid transparent;
16755
+ ${props.$arrowPosition === "right" ? `
16756
+ left: -5px;
16757
+ border-right: 6px solid ${props.theme?.colors?.background || "hsl(0 0% 100%)"};
16758
+ ` : `
16759
+ right: -5px;
16760
+ border-left: 6px solid ${props.theme?.colors?.background || "hsl(0 0% 100%)"};
16761
+ `}
16762
+ }
16763
+ `}
16764
+
16765
+ @media (max-width: 768px) {
16766
+ width: 300px;
16767
+ }
16768
+
16769
+ table {
16770
+ border-collapse: collapse;
16771
+ }
16772
+ table,
16773
+ tr,
16774
+ td,
16775
+ th {
16776
+ margin: 0;
16777
+ padding: 0;
16778
+ font-size: 0.875rem;
16779
+ color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
16780
+ text-align: left;
16781
+ }
16782
+ tr td {
16783
+ padding: 0.5rem;
16784
+ font-size: 0.75rem;
16785
+ }
16786
+ tbody tr {
16787
+ transition: transform 0.1s ease-in-out;
16788
+ }
16789
+ tbody tr:hover {
16790
+ cursor: pointer;
16791
+ background-color: ${(props)=>props.theme?.colors?.muted || "hsl(210 40% 96%)"};
16792
+ }
16793
+ tbody tr:active {
16794
+ transform: translateY(1px);
16795
+ }
16796
+ .total-row {
16797
+ border-top: 1px solid transparent;
16798
+ border-bottom: 1px solid transparent;
16799
+ font-weight: 500;
16800
+ }
16801
+ .selected-row {
16802
+ background-color: ${(props)=>props.theme?.colors?.muted || "hsl(210 40% 96%)"};
16803
+ }
16804
+ .total-row.selected-row {
16805
+ background-color: ${(props)=>props.theme?.colors?.muted || "hsl(210 40% 96%)"};
16806
+ }
16807
+ th {
16808
+ font-weight: 500;
16809
+ font-size: 0.75rem;
16810
+ border-bottom: 1px solid ${(props)=>props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
16811
+ padding-bottom: 0.5rem;
16812
+ }
16813
+ `;
16814
+ const PopoverHeader = styled.div`
16662
16815
  display: flex;
16663
- flex-direction: column;
16816
+ justify-content: space-between;
16817
+ align-items: center;
16818
+ flex-direction: row;
16819
+ padding: 0.75rem 1rem;
16820
+ border-bottom: 1px solid ${(props)=>props.theme?.colors?.border || "hsl(214.3 31.8% 91.4%)"};
16821
+ background-color: ${(props)=>props.theme?.colors?.card || "hsl(0 0% 100%)"};
16822
+ border-radius: 0.5rem 0.5rem 0 0;
16823
+ `;
16824
+ const PopoverTitle = styled.div`
16825
+ display: flex;
16826
+ align-items: center;
16664
16827
  gap: 0.5rem;
16828
+ font-weight: 600;
16829
+ font-size: 0.875rem;
16830
+ color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
16665
16831
  `;
16666
- const InputArrayScrollableContent = styled.div`
16667
- width: 100%;
16832
+ const PopoverHeaderButtons = styled.div`
16668
16833
  display: flex;
16669
- flex-direction: column;
16670
- padding-bottom: 0.5rem;
16834
+ align-items: center;
16671
16835
  gap: 0.5rem;
16672
- max-height: 200px;
16673
- overflow-y: auto;
16836
+ justify-content: flex-start;
16674
16837
  `;
16675
- const InputArrayHeader = styled.div`
16838
+ const CloseButton = styled.button`
16676
16839
  display: flex;
16677
16840
  align-items: center;
16678
- justify-content: space-between;
16679
- font-weight: 500;
16680
- font-size: 0.75rem;
16681
- color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
16841
+ justify-content: center;
16842
+ width: 24px;
16843
+ height: 24px;
16844
+ border: none;
16845
+ border-radius: 0.25rem;
16846
+ background-color: transparent;
16847
+ color: ${(props)=>props.theme?.colors?.mutedForeground || "hsl(215.4 16.3% 46.9%)"};
16848
+ cursor: pointer;
16849
+ transition: all 0.2s ease-in-out;
16682
16850
 
16683
- & h3 {
16684
- margin: 0;
16685
- padding: 0;
16686
- font-size: 0.75rem;
16687
- font-weight: 500;
16851
+ &:hover {
16852
+ background-color: ${(props)=>props.theme?.colors?.muted || "hsl(210 40% 96%)"};
16688
16853
  color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
16689
16854
  }
16690
16855
 
16691
- & span {
16692
- font-size: 0.75rem;
16693
- font-weight: 500;
16694
- opacity: 0.5;
16695
- color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
16856
+ &:focus {
16857
+ outline: 2px solid ${(props)=>props.theme?.colors?.primary || "hsl(221.2 83.2% 53.3%)"};
16858
+ outline-offset: 2px;
16696
16859
  }
16697
16860
  `;
16698
- const InputItem = styled.div`
16699
- width: 100%;
16861
+ const PopoverBody = styled.div`
16862
+ max-height: 500px;
16863
+ overflow-y: auto;
16864
+ padding: 1rem;
16700
16865
  display: flex;
16701
16866
  flex-direction: column;
16702
- gap: 0.25rem;
16867
+ gap: 1rem;
16703
16868
  `;
16704
- const InputItemHeader = styled.div`
16869
+ const Section = styled.div`
16705
16870
  display: flex;
16706
- align-items: center;
16871
+ flex-direction: column;
16872
+ gap: 0.75rem;
16873
+ `;
16874
+ const FadingSection = styled(Section)`
16875
+ animation:
16876
+ expandHeight 300ms ease-out,
16877
+ fadeInContent 200ms ease-in-out 200ms both;
16878
+
16879
+ @keyframes expandHeight {
16880
+ from {
16881
+ max-height: 0;
16882
+ overflow: hidden;
16883
+ }
16884
+ to {
16885
+ max-height: 500px; /* Adjust based on expected content height */
16886
+ overflow: visible;
16887
+ }
16888
+ }
16889
+
16890
+ @keyframes fadeInContent {
16891
+ from {
16892
+ opacity: 0;
16893
+ }
16894
+ to {
16895
+ opacity: 1;
16896
+ }
16897
+ }
16898
+ `;
16899
+ const InfoGrid = styled.div`
16900
+ display: grid;
16901
+ grid-template-columns: 1fr 1fr 1fr;
16902
+ gap: 0.75rem;
16903
+ `;
16904
+ const InfoItem = styled.div`
16905
+ display: flex;
16906
+ flex-direction: column;
16707
16907
  gap: 0.25rem;
16708
16908
  `;
16709
- const InputItemLabel = styled.span`
16710
- font-weight: 600;
16909
+ const InfoLabel = styled.span`
16711
16910
  font-size: 0.75rem;
16911
+ font-weight: 500;
16712
16912
  color: ${(props)=>props.theme?.colors?.mutedForeground || "hsl(215.4 16.3% 46.9%)"};
16713
16913
  `;
16714
- const InputItemTextarea = styled(index$1)`
16715
- box-sizing: border-box;
16716
- width: 100%;
16717
- border-radius: 0.25rem;
16718
- padding: 0.5rem;
16719
- resize: none;
16720
- font-family: inherit;
16914
+ const InfoValue = styled.span`
16721
16915
  font-size: 0.75rem;
16722
- &:focus {
16723
- outline: none;
16724
- border-color: ${(props)=>props.theme?.colors?.primary || "hsl(221.2 83.2% 53.3%)"};
16725
- box-shadow: 0 0 0 1px ${(props)=>props.theme?.colors?.primary || "hsl(221.2 83.2% 53.3%)"};
16726
- }
16727
-
16728
- transition: all 0.2s ease-in-out;
16916
+ color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
16917
+ word-break: break-word;
16918
+ `;
16919
+ const NodeIcon$3 = styled.div`
16920
+ font-size: 1.25rem;
16921
+ display: flex;
16922
+ align-items: center;
16923
+ justify-content: center;
16924
+ color: ${(props)=>props.theme?.colors?.foreground || "hsl(222.2 84% 4.9%)"};
16729
16925
  `;
16730
16926
 
16731
16927
  // Helper function to get node icon
@@ -16784,10 +16980,12 @@ const AgentNode = ({ data, id, onInspect })=>{
16784
16980
  setIsPopoverOpen(false);
16785
16981
  };
16786
16982
  const nodeLabel = data.label || toTitleCase("Agent") || "Agent";
16787
- const modelProvider = data.details?.internals?.llm_details?.[0]?.model_provider;
16983
+ const modelProvider = data.details?.internals?.llm_details?.[data.details?.internals?.llm_details?.length - 1]?.model_provider;
16788
16984
  const nodeIcon = getNodeIcon(modelProvider);
16789
- const modelName = data.details?.internals?.llm_details?.[0]?.model_name || "Unknown";
16790
- const totalCost = formatCurrency(sumTotalCost(data.details?.internals?.llm_details || []));
16985
+ const modelName = data.details?.internals?.llm_details?.[data.details?.internals?.llm_details?.length - 1]?.model_name || "Unknown";
16986
+ const totalCost = sumTotalCost(data.details?.internals?.llm_details || []);
16987
+ const totalCostFormatted = formatCurrency(totalCost, 2);
16988
+ const totalCostTooltip = `Total cost: ${formatCurrency(totalCost, 5)} USD`;
16791
16989
  const nodeDetails = getOverviewLlmDetails(data.details?.internals?.llm_details || []);
16792
16990
  const inputArray = nodeDetails?.input || [];
16793
16991
  const output = nodeDetails?.output || null;
@@ -16811,8 +17009,8 @@ const AgentNode = ({ data, id, onInspect })=>{
16811
17009
  title: modelName
16812
17010
  }, modelName), /*#__PURE__*/ React.createElement(Badge, {
16813
17011
  variant: "cost",
16814
- title: data.details?.internals?.llm_details?.[0]?.total_cost?.toString() || ""
16815
- }, totalCost))), /*#__PURE__*/ React.createElement(NodeContent$2, null, /*#__PURE__*/ React.createElement(InputArrayRenderer, {
17012
+ title: totalCostTooltip
17013
+ }, totalCostFormatted))), /*#__PURE__*/ React.createElement(NodeContent$2, null, /*#__PURE__*/ React.createElement(InputArrayRenderer, {
16816
17014
  input: inputArray
16817
17015
  }), output ? /*#__PURE__*/ React.createElement(OutputRenderer, {
16818
17016
  data: output
@@ -17015,15 +17213,25 @@ const ToolNode = ({ data, id, onInspect })=>{
17015
17213
  // Check if this node has any incoming edges (target edges)
17016
17214
  const hasIncomingEdges = data.edges?.some((edge)=>edge.target === id) || false;
17017
17215
  const handleNodeClick = ()=>{
17018
- // Console log the node data for Tool nodes
17019
- console.log("Tool node clicked:", {
17020
- label: data.label,
17021
- nodeType: data.nodeType,
17022
- details: data.details
17023
- });
17216
+ if (onInspect) {
17217
+ onInspect(data);
17218
+ }
17024
17219
  };
17025
17220
  const nodeLabel = data.label || toTitleCase("Tool") || "Tool";
17026
17221
  const latency = data.details?.internals?.latency?.total_time;
17222
+ let nodeData = null;
17223
+ const baseData = data.details?.internals || {};
17224
+ if (data.edgeDetails && data.edgeDetails.length > 0) {
17225
+ nodeData = {
17226
+ ...baseData,
17227
+ input: {
17228
+ args: data.edgeDetails[0]?.input_args,
17229
+ kwargs: data.edgeDetails[0]?.input_kwargs
17230
+ },
17231
+ output: data.edgeDetails[0]?.output,
17232
+ status: data.edgeDetails[0]?.status
17233
+ };
17234
+ }
17027
17235
  return /*#__PURE__*/ React.createElement(NodeContainer, {
17028
17236
  onClick: handleNodeClick
17029
17237
  }, hasIncomingEdges && /*#__PURE__*/ React.createElement(Handle$1, {
@@ -17039,25 +17247,13 @@ const ToolNode = ({ data, id, onInspect })=>{
17039
17247
  isConnectable: false
17040
17248
  }), /*#__PURE__*/ React.createElement(NodeHeader, null, /*#__PURE__*/ React.createElement(NodeIconContainer, null, /*#__PURE__*/ React.createElement(NodeIcon, null, "🔧"), /*#__PURE__*/ React.createElement(NodeLabel, null, nodeLabel)), latency != null && /*#__PURE__*/ React.createElement(BadgeContainer, null, /*#__PURE__*/ React.createElement(Badge, {
17041
17249
  variant: "latency"
17042
- }, formatLatency(latency)))), /*#__PURE__*/ React.createElement(NodeContent, null, /*#__PURE__*/ React.createElement(JsonTreeViewer, {
17250
+ }, formatLatency(latency)))), nodeData && /*#__PURE__*/ React.createElement(NodeContent, {
17251
+ className: "nodrag"
17252
+ }, /*#__PURE__*/ React.createElement(JsonTreeViewer, {
17043
17253
  excludeKeys: [
17044
17254
  "latency"
17045
17255
  ],
17046
- data: (()=>{
17047
- const baseData = data.details?.internals || {};
17048
- if (data.edgeDetails && data.edgeDetails.length > 0) {
17049
- return {
17050
- ...baseData,
17051
- input: {
17052
- args: data.edgeDetails[0]?.input_args,
17053
- kwargs: data.edgeDetails[0]?.input_kwargs
17054
- },
17055
- output: data.edgeDetails[0]?.output,
17056
- status: data.edgeDetails[0]?.status
17057
- };
17058
- }
17059
- return baseData;
17060
- })()
17256
+ data: nodeData
17061
17257
  })), hasOutgoingEdges && /*#__PURE__*/ React.createElement(Handle$1, {
17062
17258
  type: "source",
17063
17259
  position: Position.Bottom,