@railtownai/railtracks-visualizer 0.0.33 → 0.0.34

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,18 +14732,66 @@ 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 (USD dollars)
14735
+ * Formats a currency value (USD dollars) with dynamic precision
14736
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) {
14737
+ * @returns The formatted dollar string with appropriate precision
14738
+ */ function formatCurrency(value) {
14740
14739
  if (value === null || value === undefined) {
14741
- return "$0.000";
14740
+ return "$0.00";
14741
+ }
14742
+ const absValue = Math.abs(value);
14743
+ // Handle zero
14744
+ if (absValue === 0) {
14745
+ return "$0.00";
14746
+ }
14747
+ // Handle whole numbers - format with 3 decimal places
14748
+ if (Number.isInteger(absValue)) {
14749
+ const sign = value < 0 ? "-" : "";
14750
+ return `${sign}$${absValue.toFixed(3)}`;
14751
+ }
14752
+ // For decimal numbers, find the first non-zero decimal place
14753
+ const valueStr = absValue.toString();
14754
+ const decimalIndex = valueStr.indexOf(".");
14755
+ if (decimalIndex === -1) {
14756
+ // No decimal point, treat as whole number
14757
+ const sign = value < 0 ? "-" : "";
14758
+ return `${sign}$${absValue.toFixed(3)}`;
14759
+ }
14760
+ // Find the first non-zero digit after the decimal point
14761
+ let precision = 1;
14762
+ const decimalPart = valueStr.substring(decimalIndex + 1);
14763
+ for(let i = 0; i < decimalPart.length; i++){
14764
+ if (decimalPart[i] !== "0") {
14765
+ precision = i + 1;
14766
+ break;
14767
+ }
14768
+ }
14769
+ // For values >= 1, ensure we show at least 3 decimal places for readability
14770
+ if (absValue >= 1) {
14771
+ precision = Math.max(precision, 3);
14742
14772
  }
14743
- // Format the dollar value with sp ecified precision
14744
- const formatted = Math.abs(value).toFixed(precision);
14773
+ // Cap precision at 8 decimal places
14774
+ precision = Math.min(precision, 8);
14775
+ // Check if the value rounds to a whole number when rounded to the nearest integer
14776
+ // This handles cases like 123.999 -> 124.000, but only if the value is very close to a whole number
14777
+ const roundedToInteger = Math.round(absValue);
14778
+ if (roundedToInteger >= 1 && Number.isInteger(roundedToInteger) && Math.abs(absValue - roundedToInteger) < 0.01) {
14779
+ const sign = value < 0 ? "-" : "";
14780
+ return `${sign}$${roundedToInteger.toFixed(3)}`;
14781
+ }
14782
+ // Round to the determined precision
14783
+ const rounded = absValue.toFixed(precision);
14745
14784
  const sign = value < 0 ? "-" : "";
14746
- return `${sign}$${formatted}`;
14785
+ const roundedNum = parseFloat(rounded);
14786
+ // If the result is effectively zero (like $0.00000000), display as $0.00
14787
+ if (roundedNum === 0 || rounded === "0.00000000") {
14788
+ return "$0.00";
14789
+ }
14790
+ // If the rounded value is a whole number and >= 1, show 3 decimal places
14791
+ if (roundedNum >= 1 && Number.isInteger(roundedNum)) {
14792
+ return `${sign}$${roundedNum.toFixed(3)}`;
14793
+ }
14794
+ return `${sign}$${rounded}`;
14747
14795
  }
14748
14796
  /**
14749
14797
  * Formats latency in a human-readable format
@@ -16359,7 +16407,7 @@ const CountUpCurrency = ({ value, prefix = "", suffix = "" })=>{
16359
16407
  end: value,
16360
16408
  duration: DEFAULT_COUNTUP_DURATION,
16361
16409
  separator: ",",
16362
- decimals: 2,
16410
+ decimals: 3,
16363
16411
  decimal: ".",
16364
16412
  prefix: prefix,
16365
16413
  useEasing: true,
@@ -16986,8 +17034,8 @@ const AgentNode = ({ data, id, onInspect })=>{
16986
17034
  const nodeIcon = getNodeIcon(modelProvider);
16987
17035
  const modelName = data.details?.internals?.llm_details?.[data.details?.internals?.llm_details?.length - 1]?.model_name || "Unknown";
16988
17036
  const totalCost = sumTotalCost(data.details?.internals?.llm_details || []);
16989
- const totalCostFormatted = formatCurrency(totalCost, 2);
16990
- const totalCostTooltip = `Total cost: ${formatCurrency(totalCost, 5)} USD`;
17037
+ const totalCostFormatted = formatCurrency(totalCost);
17038
+ const totalCostTooltip = `Total cost: ${formatCurrency(totalCost)} USD`;
16991
17039
  const nodeDetails = getOverviewLlmDetails(data.details?.internals?.llm_details || []);
16992
17040
  const inputArray = nodeDetails?.input || [];
16993
17041
  const output = nodeDetails?.output || null;
@@ -20199,7 +20247,7 @@ const nodeTypes = {
20199
20247
  const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100dvw", height = "100dvh", className = "", defaultZoom = 1, defaultPan = {
20200
20248
  x: 0,
20201
20249
  y: 0
20202
- }, disableAutoFit = true, defaultAutoFitDuration = 1000, defaultAutoFitDelay = 250, showTimeline = false, minNodeSpacing = 300, onInspect })=>{
20250
+ }, disableAutoFit = true, defaultAutoFitDuration = 1000, defaultAutoFitDelay = 250, showTimeline = false, minNodeSpacing = 300, onInspect, panToNodeId })=>{
20203
20251
  const { theme, isDarkMode } = useTheme();
20204
20252
  const themeColors = theme.colors;
20205
20253
  // Helper function to determine if we should apply minimum dimensions
@@ -20545,6 +20593,39 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100dvw", heigh
20545
20593
  defaultAutoFitDuration,
20546
20594
  defaultAutoFitDelay
20547
20595
  ]);
20596
+ // Pan to specific node when panToNodeId prop is provided
20597
+ React.useEffect(()=>{
20598
+ if (!panToNodeId || !reactFlowInstance || disableAutoFit || nodes.length === 0) {
20599
+ return;
20600
+ }
20601
+ // Check if the specified node ID exists in the current nodes array
20602
+ const targetNode = nodes.find((node)=>node.id === panToNodeId);
20603
+ if (!targetNode) {
20604
+ return;
20605
+ }
20606
+ // Pan to the specified node
20607
+ setTimeout(()=>{
20608
+ reactFlowInstance.fitView({
20609
+ nodes: [
20610
+ {
20611
+ id: panToNodeId
20612
+ }
20613
+ ],
20614
+ duration: defaultAutoFitDuration,
20615
+ padding: 0.2,
20616
+ minZoom: defaultZoom,
20617
+ maxZoom: defaultZoom
20618
+ });
20619
+ }, defaultAutoFitDelay);
20620
+ }, [
20621
+ panToNodeId,
20622
+ reactFlowInstance,
20623
+ disableAutoFit,
20624
+ nodes,
20625
+ defaultAutoFitDuration,
20626
+ defaultAutoFitDelay,
20627
+ defaultZoom
20628
+ ]);
20548
20629
  return /*#__PURE__*/ React.createElement("div", {
20549
20630
  ref: containerRef,
20550
20631
  style: {
package/dist/esm/index.js CHANGED
@@ -14712,18 +14712,66 @@ 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 (USD dollars)
14715
+ * Formats a currency value (USD dollars) with dynamic precision
14716
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) {
14717
+ * @returns The formatted dollar string with appropriate precision
14718
+ */ function formatCurrency(value) {
14720
14719
  if (value === null || value === undefined) {
14721
- return "$0.000";
14720
+ return "$0.00";
14721
+ }
14722
+ const absValue = Math.abs(value);
14723
+ // Handle zero
14724
+ if (absValue === 0) {
14725
+ return "$0.00";
14726
+ }
14727
+ // Handle whole numbers - format with 3 decimal places
14728
+ if (Number.isInteger(absValue)) {
14729
+ const sign = value < 0 ? "-" : "";
14730
+ return `${sign}$${absValue.toFixed(3)}`;
14731
+ }
14732
+ // For decimal numbers, find the first non-zero decimal place
14733
+ const valueStr = absValue.toString();
14734
+ const decimalIndex = valueStr.indexOf(".");
14735
+ if (decimalIndex === -1) {
14736
+ // No decimal point, treat as whole number
14737
+ const sign = value < 0 ? "-" : "";
14738
+ return `${sign}$${absValue.toFixed(3)}`;
14739
+ }
14740
+ // Find the first non-zero digit after the decimal point
14741
+ let precision = 1;
14742
+ const decimalPart = valueStr.substring(decimalIndex + 1);
14743
+ for(let i = 0; i < decimalPart.length; i++){
14744
+ if (decimalPart[i] !== "0") {
14745
+ precision = i + 1;
14746
+ break;
14747
+ }
14748
+ }
14749
+ // For values >= 1, ensure we show at least 3 decimal places for readability
14750
+ if (absValue >= 1) {
14751
+ precision = Math.max(precision, 3);
14722
14752
  }
14723
- // Format the dollar value with sp ecified precision
14724
- const formatted = Math.abs(value).toFixed(precision);
14753
+ // Cap precision at 8 decimal places
14754
+ precision = Math.min(precision, 8);
14755
+ // Check if the value rounds to a whole number when rounded to the nearest integer
14756
+ // This handles cases like 123.999 -> 124.000, but only if the value is very close to a whole number
14757
+ const roundedToInteger = Math.round(absValue);
14758
+ if (roundedToInteger >= 1 && Number.isInteger(roundedToInteger) && Math.abs(absValue - roundedToInteger) < 0.01) {
14759
+ const sign = value < 0 ? "-" : "";
14760
+ return `${sign}$${roundedToInteger.toFixed(3)}`;
14761
+ }
14762
+ // Round to the determined precision
14763
+ const rounded = absValue.toFixed(precision);
14725
14764
  const sign = value < 0 ? "-" : "";
14726
- return `${sign}$${formatted}`;
14765
+ const roundedNum = parseFloat(rounded);
14766
+ // If the result is effectively zero (like $0.00000000), display as $0.00
14767
+ if (roundedNum === 0 || rounded === "0.00000000") {
14768
+ return "$0.00";
14769
+ }
14770
+ // If the rounded value is a whole number and >= 1, show 3 decimal places
14771
+ if (roundedNum >= 1 && Number.isInteger(roundedNum)) {
14772
+ return `${sign}$${roundedNum.toFixed(3)}`;
14773
+ }
14774
+ return `${sign}$${rounded}`;
14727
14775
  }
14728
14776
  /**
14729
14777
  * Formats latency in a human-readable format
@@ -16339,7 +16387,7 @@ const CountUpCurrency = ({ value, prefix = "", suffix = "" })=>{
16339
16387
  end: value,
16340
16388
  duration: DEFAULT_COUNTUP_DURATION,
16341
16389
  separator: ",",
16342
- decimals: 2,
16390
+ decimals: 3,
16343
16391
  decimal: ".",
16344
16392
  prefix: prefix,
16345
16393
  useEasing: true,
@@ -16966,8 +17014,8 @@ const AgentNode = ({ data, id, onInspect })=>{
16966
17014
  const nodeIcon = getNodeIcon(modelProvider);
16967
17015
  const modelName = data.details?.internals?.llm_details?.[data.details?.internals?.llm_details?.length - 1]?.model_name || "Unknown";
16968
17016
  const totalCost = sumTotalCost(data.details?.internals?.llm_details || []);
16969
- const totalCostFormatted = formatCurrency(totalCost, 2);
16970
- const totalCostTooltip = `Total cost: ${formatCurrency(totalCost, 5)} USD`;
17017
+ const totalCostFormatted = formatCurrency(totalCost);
17018
+ const totalCostTooltip = `Total cost: ${formatCurrency(totalCost)} USD`;
16971
17019
  const nodeDetails = getOverviewLlmDetails(data.details?.internals?.llm_details || []);
16972
17020
  const inputArray = nodeDetails?.input || [];
16973
17021
  const output = nodeDetails?.output || null;
@@ -20179,7 +20227,7 @@ const nodeTypes = {
20179
20227
  const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100dvw", height = "100dvh", className = "", defaultZoom = 1, defaultPan = {
20180
20228
  x: 0,
20181
20229
  y: 0
20182
- }, disableAutoFit = true, defaultAutoFitDuration = 1000, defaultAutoFitDelay = 250, showTimeline = false, minNodeSpacing = 300, onInspect })=>{
20230
+ }, disableAutoFit = true, defaultAutoFitDuration = 1000, defaultAutoFitDelay = 250, showTimeline = false, minNodeSpacing = 300, onInspect, panToNodeId })=>{
20183
20231
  const { theme, isDarkMode } = useTheme();
20184
20232
  const themeColors = theme.colors;
20185
20233
  // Helper function to determine if we should apply minimum dimensions
@@ -20525,6 +20573,39 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100dvw", heigh
20525
20573
  defaultAutoFitDuration,
20526
20574
  defaultAutoFitDelay
20527
20575
  ]);
20576
+ // Pan to specific node when panToNodeId prop is provided
20577
+ useEffect(()=>{
20578
+ if (!panToNodeId || !reactFlowInstance || disableAutoFit || nodes.length === 0) {
20579
+ return;
20580
+ }
20581
+ // Check if the specified node ID exists in the current nodes array
20582
+ const targetNode = nodes.find((node)=>node.id === panToNodeId);
20583
+ if (!targetNode) {
20584
+ return;
20585
+ }
20586
+ // Pan to the specified node
20587
+ setTimeout(()=>{
20588
+ reactFlowInstance.fitView({
20589
+ nodes: [
20590
+ {
20591
+ id: panToNodeId
20592
+ }
20593
+ ],
20594
+ duration: defaultAutoFitDuration,
20595
+ padding: 0.2,
20596
+ minZoom: defaultZoom,
20597
+ maxZoom: defaultZoom
20598
+ });
20599
+ }, defaultAutoFitDelay);
20600
+ }, [
20601
+ panToNodeId,
20602
+ reactFlowInstance,
20603
+ disableAutoFit,
20604
+ nodes,
20605
+ defaultAutoFitDuration,
20606
+ defaultAutoFitDelay,
20607
+ defaultZoom
20608
+ ]);
20528
20609
  return /*#__PURE__*/ React__default.createElement("div", {
20529
20610
  ref: containerRef,
20530
20611
  style: {
@@ -17,6 +17,7 @@ export interface AgenticFlowVisualizerProps {
17
17
  showTimeline?: boolean;
18
18
  minNodeSpacing?: number;
19
19
  onInspect?: (nodeData: any) => void;
20
+ panToNodeId?: string;
20
21
  }
21
22
  declare const AgenticFlowVisualizer: React.FC<AgenticFlowVisualizerProps>;
22
23
  export default AgenticFlowVisualizer;
@@ -8,12 +8,11 @@ export declare function cn(...inputs: ClassValue[]): string;
8
8
  */
9
9
  export declare function toTitleCase(str: string): string;
10
10
  /**
11
- * Formats a currency value (USD dollars)
11
+ * Formats a currency value (USD dollars) with dynamic precision
12
12
  * @param value - The dollar value to format
13
- * @param precision - The number of decimal places to show. Defaults to 3.
14
- * @returns The formatted dollar string (eg: $123.002)
13
+ * @returns The formatted dollar string with appropriate precision
15
14
  */
16
- export declare function formatCurrency(value: number | null | undefined, precision?: number): string;
15
+ export declare function formatCurrency(value: number | null | undefined): string;
17
16
  /**
18
17
  * Formats latency in a human-readable format
19
18
  * @param latency - Latency in seconds
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@railtownai/railtracks-visualizer",
3
- "version": "0.0.33",
3
+ "version": "0.0.34",
4
4
  "license": "MIT",
5
5
  "author": "Railtown AI",
6
6
  "description": "A visualizer for RailTracks agentic flows",