@railtownai/railtracks-visualizer 0.0.32 → 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
|
-
* @
|
|
14738
|
-
|
|
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.
|
|
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
|
-
//
|
|
14744
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
16990
|
-
const totalCostTooltip = `Total cost: ${formatCurrency(totalCost
|
|
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: {
|
|
@@ -20703,9 +20784,9 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100dvw", heigh
|
|
|
20703
20784
|
}
|
|
20704
20785
|
}
|
|
20705
20786
|
}, /*#__PURE__*/ React.createElement(Background, {
|
|
20706
|
-
variant: BackgroundVariant.
|
|
20787
|
+
variant: BackgroundVariant.Dots,
|
|
20707
20788
|
color: themeColors.mutedBorder,
|
|
20708
|
-
|
|
20789
|
+
size: 3
|
|
20709
20790
|
})), /*#__PURE__*/ React.createElement("style", null, `
|
|
20710
20791
|
.react-flow__edge-label {
|
|
20711
20792
|
font-size: 10px;
|
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
|
-
* @
|
|
14718
|
-
|
|
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.
|
|
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
|
-
//
|
|
14724
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
16970
|
-
const totalCostTooltip = `Total cost: ${formatCurrency(totalCost
|
|
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: {
|
|
@@ -20683,9 +20764,9 @@ const AgenticFlowVisualizer = ({ flowData: propFlowData, width = "100dvw", heigh
|
|
|
20683
20764
|
}
|
|
20684
20765
|
}
|
|
20685
20766
|
}, /*#__PURE__*/ React__default.createElement(Background, {
|
|
20686
|
-
variant: BackgroundVariant.
|
|
20767
|
+
variant: BackgroundVariant.Dots,
|
|
20687
20768
|
color: themeColors.mutedBorder,
|
|
20688
|
-
|
|
20769
|
+
size: 3
|
|
20689
20770
|
})), /*#__PURE__*/ React__default.createElement("style", null, `
|
|
20690
20771
|
.react-flow__edge-label {
|
|
20691
20772
|
font-size: 10px;
|
|
@@ -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
|
-
* @
|
|
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
|
|
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
|