@railtownai/railtracks-visualizer 0.0.27 → 0.0.28

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