@cognizant-ai-lab/ui-common 1.9.0 → 1.10.0
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/components/AgentChat/ChatCommon/ChatCommon.js +5 -4
- package/dist/components/AgentChat/ChatCommon/Thinking.js +2 -2
- package/dist/components/AgentChat/Common/Utils.d.ts +0 -11
- package/dist/components/AgentChat/Common/Utils.js +0 -16
- package/dist/components/Common/Footer.js +4 -0
- package/dist/components/MultiAgentAccelerator/AgentFlow/AgentFlow.js +56 -24
- package/dist/components/MultiAgentAccelerator/AgentFlow/AgentNode.js +7 -5
- package/dist/components/MultiAgentAccelerator/AgentFlow/GraphLayouts.js +10 -7
- package/dist/components/MultiAgentAccelerator/AgentFlow/GraphStructure.d.ts +1 -1
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +9 -56
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.d.ts +2 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.js +23 -31
- package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.d.ts +0 -2
- package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.js +7 -6
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.d.ts +2 -2
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.js +13 -13
- package/dist/components/MultiAgentAccelerator/TemporaryNetworks.d.ts +3 -17
- package/dist/components/MultiAgentAccelerator/TemporaryNetworks.js +17 -40
- package/dist/components/MultiAgentAccelerator/Tour/MainTourSteps.js +2 -2
- package/dist/components/MultiAgentAccelerator/const.d.ts +11 -11
- package/dist/components/MultiAgentAccelerator/const.js +22 -22
- package/dist/state/TemporaryNetworks.js +12 -21
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/AgentName.d.ts +17 -0
- package/dist/utils/AgentName.js +46 -0
- package/package.json +1 -1
- package/dist/components/MultiAgentAccelerator/Sidebar/ImportNetworkModal.d.ts +0 -67
- package/dist/components/MultiAgentAccelerator/Sidebar/ImportNetworkModal.js +0 -585
|
@@ -9,14 +9,18 @@ import Edit from "@mui/icons-material/Edit";
|
|
|
9
9
|
import Box from "@mui/material/Box";
|
|
10
10
|
import Chip from "@mui/material/Chip";
|
|
11
11
|
import IconButton from "@mui/material/IconButton";
|
|
12
|
+
import { styled } from "@mui/material/styles";
|
|
12
13
|
import Tooltip from "@mui/material/Tooltip";
|
|
13
14
|
import { useTreeItemModel } from "@mui/x-tree-view/hooks";
|
|
14
15
|
import { TreeItemContent, TreeItemGroupTransition, TreeItemLabel, TreeItemRoot, } from "@mui/x-tree-view/TreeItem";
|
|
15
16
|
import { TreeItemProvider } from "@mui/x-tree-view/TreeItemProvider";
|
|
16
17
|
import { useTreeItem } from "@mui/x-tree-view/useTreeItem";
|
|
17
18
|
import { useRef } from "react";
|
|
18
|
-
import { downloadFile
|
|
19
|
-
|
|
19
|
+
import { downloadFile } from "../../../utils/File.js";
|
|
20
|
+
//#region Constants
|
|
21
|
+
// Accessible names shared between each action's tooltip title and its aria-label.
|
|
22
|
+
export const EDIT_NETWORK_LABEL = "Edit this network";
|
|
23
|
+
export const DOWNLOAD_NETWORK_DEFINITION_LABEL = "Download network definition";
|
|
20
24
|
// Palette of colors we can use for tags
|
|
21
25
|
const TAG_COLORS = [
|
|
22
26
|
"--bs-accent2-light",
|
|
@@ -29,6 +33,17 @@ const TAG_COLORS = [
|
|
|
29
33
|
"--bs-secondary",
|
|
30
34
|
"--bs-yellow",
|
|
31
35
|
];
|
|
36
|
+
// Shared styling for the row's action buttons (download, edit, ...). Disabled state keeps the base
|
|
37
|
+
// color and only dims via opacity.
|
|
38
|
+
const ActionIconButton = styled(IconButton)({
|
|
39
|
+
padding: 0,
|
|
40
|
+
color: "var(--bs-secondary)",
|
|
41
|
+
"&:hover": { color: "var(--bs-secondary-dark)" },
|
|
42
|
+
"&.Mui-disabled": {
|
|
43
|
+
opacity: 0.3,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
//#endregion Types and Interfaces
|
|
32
47
|
// Keep track of which tags have which colors so that the same tag always has the same color
|
|
33
48
|
const tagsToColors = new Map();
|
|
34
49
|
/**
|
|
@@ -46,8 +61,6 @@ const isTemporaryNetworkExpired = (expirationDate) => {
|
|
|
46
61
|
*/
|
|
47
62
|
export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, onDeleteNetwork, onEditNetwork, }) => {
|
|
48
63
|
const item = useTreeItemModel(itemId);
|
|
49
|
-
// We know all labels are strings because we set them that way in the tree view items
|
|
50
|
-
const labelString = label;
|
|
51
64
|
const { getContextProviderProps, getRootProps, getContentProps, getLabelProps, getGroupTransitionProps } = useTreeItem({ itemId, children, label, disabled });
|
|
52
65
|
const rootRef = useRef(null);
|
|
53
66
|
const isParent = Array.isArray(children) && children.length > 0;
|
|
@@ -64,7 +77,7 @@ export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, onDele
|
|
|
64
77
|
const expirationTime = item?.temporaryNetworkExpirationTime;
|
|
65
78
|
const isTemporaryNetwork = Boolean(expirationTime);
|
|
66
79
|
const isExpired = isChild && isTemporaryNetwork && isTemporaryNetworkExpired(expirationTime);
|
|
67
|
-
const
|
|
80
|
+
const networkHocon = item?.temporaryNetworkHocon ?? null;
|
|
68
81
|
const iconNameSuggestion = item.iconSuggestion;
|
|
69
82
|
let muiIconElement;
|
|
70
83
|
// If the item is a child (i.e., a network), we want to render an icon next to it.
|
|
@@ -106,41 +119,20 @@ export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, onDele
|
|
|
106
119
|
.map((tag) => (_jsx(Chip, { label: tag, style: {
|
|
107
120
|
margin: "0.25rem",
|
|
108
121
|
backgroundColor: `var(${tagsToColors.get(tag) || TAG_COLORS[0]})`,
|
|
109
|
-
} }, tag))), placement: "right", arrow: true, children: _jsx(BookmarkIcon, { sx: { fontSize: "0.75rem", color: "var(--bs-accent1-medium)" } }) })) : null] }), isChild && isTemporaryNetwork && (_jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: "0.25rem", marginLeft: "auto" }, children: [
|
|
122
|
+
} }, tag))), placement: "right", arrow: true, children: _jsx(BookmarkIcon, { sx: { fontSize: "0.75rem", color: "var(--bs-accent1-medium)" } }) })) : null] }), isChild && isTemporaryNetwork && (_jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: "0.25rem", marginLeft: "auto" }, children: [networkHocon && (_jsx(Tooltip, { title: isExpired ? "Expired" : DOWNLOAD_NETWORK_DEFINITION_LABEL, children: _jsx("span", { children: _jsx(ActionIconButton, { onClick: (e) => {
|
|
123
|
+
// The button is disabled while expired, so no need to guard here.
|
|
110
124
|
e.stopPropagation();
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// otherwise flatten the UUID's hyphens to underscores).
|
|
114
|
-
const cleanName = removeTrailingUuid(labelString);
|
|
115
|
-
const fileName = `${toSafeFilename(cleanName)}.json`;
|
|
116
|
-
downloadFile(JSON.stringify(networkDefinition, null, 2), fileName, "application/json");
|
|
117
|
-
}, disabled: isExpired, "aria-label": "Download network definition", size: "small", sx: {
|
|
118
|
-
padding: 0,
|
|
119
|
-
color: "var(--bs-secondary)",
|
|
120
|
-
"&:hover": { color: "var(--bs-secondary-dark)" },
|
|
121
|
-
"&.Mui-disabled": {
|
|
122
|
-
color: "var(--bs-secondary)",
|
|
123
|
-
opacity: 0.3,
|
|
124
|
-
},
|
|
125
|
-
}, children: _jsx(DownloadIcon, { sx: { fontSize: "0.75rem" } }) }) }) })), _jsx(Tooltip, { title: "Edit this network", children: _jsx("span", { children: _jsx(IconButton, { onClick: (e) => {
|
|
125
|
+
downloadFile(networkHocon, item.downloadFileName, "text/plain");
|
|
126
|
+
}, disabled: isExpired, "aria-label": DOWNLOAD_NETWORK_DEFINITION_LABEL, size: "small", children: _jsx(DownloadIcon, { sx: { fontSize: "0.75rem" } }) }) }) })), _jsx(Tooltip, { title: EDIT_NETWORK_LABEL, children: _jsx("span", { children: _jsx(ActionIconButton, { onClick: (e) => {
|
|
126
127
|
e.stopPropagation();
|
|
127
128
|
onEditNetwork?.(itemId);
|
|
128
|
-
}, disabled: isExpired, size: "small", sx: {
|
|
129
|
-
padding: 0,
|
|
130
|
-
color: "var(--bs-secondary)",
|
|
131
|
-
"&:hover": { color: "var(--bs-secondary-dark)" },
|
|
132
|
-
"&.Mui-disabled": {
|
|
133
|
-
color: "var(--bs-secondary)",
|
|
134
|
-
opacity: 0.3,
|
|
135
|
-
},
|
|
136
|
-
}, children: _jsx(Edit, { sx: { fontSize: "0.75rem" } }) }) }) }), _jsx(Tooltip, { title: "Delete network", children: _jsx(Delete, { onClick: (e) => {
|
|
129
|
+
}, disabled: isExpired, "aria-label": EDIT_NETWORK_LABEL, size: "small", children: _jsx(Edit, { sx: { fontSize: "0.75rem" } }) }) }) }), _jsx(Tooltip, { title: "Delete network", children: _jsx(Delete, { onClick: (e) => {
|
|
137
130
|
e.stopPropagation();
|
|
138
131
|
onDeleteNetwork?.(itemId, isExpired);
|
|
139
132
|
}, sx: {
|
|
140
133
|
color: "var(--bs-secondary)",
|
|
141
134
|
"&:hover": { color: (theme) => theme.palette.warning.main },
|
|
142
135
|
"&.Mui-disabled": {
|
|
143
|
-
color: "var(--bs-secondary)",
|
|
144
136
|
opacity: 0.3,
|
|
145
137
|
},
|
|
146
138
|
cursor: "pointer",
|
|
@@ -6,14 +6,12 @@ export declare const SPARKLE_HIGHLIGHT_CLASS = "sparkle-highlight";
|
|
|
6
6
|
export interface SidebarProps {
|
|
7
7
|
readonly id: string;
|
|
8
8
|
readonly isAwaitingLlm: boolean;
|
|
9
|
-
readonly isImporting: boolean;
|
|
10
9
|
readonly networkIconSuggestions?: NetworkIconSuggestions;
|
|
11
10
|
readonly networks: readonly AgentInfo[];
|
|
12
11
|
readonly neuroSanServerURL: string;
|
|
13
12
|
readonly newlyAddedTemporaryNetworks?: Set<string>;
|
|
14
13
|
readonly onDeleteNetwork?: (network: string, isExpired: boolean) => void;
|
|
15
14
|
readonly onEditNetwork?: (network: string) => void;
|
|
16
|
-
readonly onImportClick?: () => void;
|
|
17
15
|
readonly setSelectedNetwork: (network: string) => void;
|
|
18
16
|
readonly temporaryNetworks?: readonly TemporaryNetwork[];
|
|
19
17
|
}
|
|
@@ -15,7 +15,6 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import AddBoxRounded from "@mui/icons-material/AddBoxRounded";
|
|
18
|
-
import FileUploadOutlinedIcon from "@mui/icons-material/FileUploadOutlined";
|
|
19
18
|
import Box from "@mui/material/Box";
|
|
20
19
|
import Button from "@mui/material/Button";
|
|
21
20
|
import { keyframes, styled } from "@mui/material/styles";
|
|
@@ -116,7 +115,7 @@ const ServerStatusTooltip = styled(({ className, ...props }) => (_jsx(Tooltip, {
|
|
|
116
115
|
},
|
|
117
116
|
});
|
|
118
117
|
//#endregion: Types
|
|
119
|
-
export const Sidebar = ({ id, isAwaitingLlm,
|
|
118
|
+
export const Sidebar = ({ id, isAwaitingLlm, networkIconSuggestions, networks, neuroSanServerURL, newlyAddedTemporaryNetworks, onDeleteNetwork, onEditNetwork, setSelectedNetwork, temporaryNetworks = EMPTY_ARRAY, }) => {
|
|
120
119
|
const [expandedItems, setExpandedItems] = useState([]);
|
|
121
120
|
const [selectedItem, setSelectedItem] = useState(null);
|
|
122
121
|
// Display option for agent/network names
|
|
@@ -215,10 +214,12 @@ export const Sidebar = ({ id, isAwaitingLlm, isImporting, networkIconSuggestions
|
|
|
215
214
|
"aria-label": "Neuro-san server status",
|
|
216
215
|
},
|
|
217
216
|
}, title: _jsxs(Box, { sx: { display: "flex", flexDirection: "column", gap: 0.5 }, children: [_jsxs(Typography, { variant: "body2", children: [_jsx("strong", { children: "Status:" }), " ", mapStatus(neuroSanServerStatus?.statusText)] }), _jsxs(Typography, { variant: "body2", children: [_jsx("strong", { children: "URL:" }), " ", neuroSanServerURL || "unknown"] }), _jsxs(Typography, { variant: "body2", children: [_jsx("strong", { children: "Service:" }), " ", neuroSanServerStatus?.healthCheckResponse?.service || "unknown"] }), _jsx(Typography, { sx: { fontWeight: "bold" }, variant: "body2", children: "Versions:" }), _jsxs(Box, { sx: { ml: 1 }, children: [_jsxs(Typography, { variant: "body2", children: [_jsx("strong", { children: "Neuro SAN:" }), " ", neuroSanServerStatus?.healthCheckResponse?.versions?.["neuro-san"] ?? "unknown"] }), _jsxs(Typography, { variant: "body2", children: [_jsx("strong", { children: "Neuro SAN Studio:" }), " ", neuroSanServerStatus?.healthCheckResponse?.versions?.["neuro-san-studio"] ?? "unknown"] })] }), !neuroSanServerStatus?.success && neuroSanServerStatus?.httpStatus && (_jsx(_Fragment, { children: _jsxs(Typography, { variant: "body2", children: [_jsx("strong", { children: "HTTP status:" }), " ", `${neuroSanServerStatus.httpStatus} (${httpStatus[neuroSanServerStatus.httpStatus] ?? "Unknown status"})`] }) }))] }), placement: "right", children: _jsx("span", { children: _jsx(StatusLight, { id: `${id}-agent-network-status-light`, statusValue: toStatusColor() }) }) }));
|
|
218
|
-
const getAddNetworkButton = () => (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
217
|
+
const getAddNetworkButton = () => (_jsx(Box, { sx: { display: "flex" }, children: _jsx(Button, { "aria-label": "Add New Network", disabled: isAwaitingLlm, id: "add-network-btn", onClick: () => {
|
|
218
|
+
setSelectedItem(AGENT_NETWORK_DESIGNER_ID);
|
|
219
|
+
setSelectedNetwork(AGENT_NETWORK_DESIGNER_ID);
|
|
220
|
+
}, sx: { display: "inline-block", minWidth: "40px" }, children: _jsx(Tooltip, { title: "Create your own agent network", placement: "top", children: _jsx(AddBoxRounded, { id: "add-network-icon", sx: (theme) => ({
|
|
221
|
+
color: isAwaitingLlm ? theme.palette.action.disabled : "var(--bs-secondary)",
|
|
222
|
+
}) }) }) }) }));
|
|
222
223
|
const getSidebarHeading = () => (_jsxs(SidebarHeading, { id: `${id}-heading`, children: [_jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: (theme) => theme.spacing(1.5) }, children: [getStatusLight(), "Agent Networks"] }), getAddNetworkButton()] }));
|
|
223
224
|
const getSidebarNetworksTree = () => (_jsx(RichTreeView, { disableSelection: isAwaitingLlm, expandedItems: expandedItems, items: treeViewItems, multiSelect: false, onExpandedItemsChange: (_event, itemIds) => setExpandedItems(itemIds), onSelectedItemsChange: handleSelectedItemsChange, selectedItems: selectedItem, slotProps: {
|
|
224
225
|
item: { onDeleteNetwork, onEditNetwork: handleEditNetworkWithSelect },
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { TreeViewDefaultItemModelProperties } from "@mui/x-tree-view/models";
|
|
2
2
|
import { AgentInfo } from "../../../generated/neuro-san/NeuroSanClient.js";
|
|
3
3
|
import { TemporaryNetwork } from "../../../state/TemporaryNetworks.js";
|
|
4
|
-
import { AgentNetworkDefinitionEntry } from "../const.js";
|
|
5
4
|
/**
|
|
6
5
|
* Represents either a category (folder) or a network (leaf) in the tree view.
|
|
7
6
|
* Note that we omit the `children` property from the parent as we want to use read-only semantics
|
|
@@ -9,11 +8,12 @@ import { AgentNetworkDefinitionEntry } from "../const.js";
|
|
|
9
8
|
export interface AgentNetworkTreeItemModel extends Omit<TreeViewDefaultItemModelProperties, "children"> {
|
|
10
9
|
readonly children?: readonly AgentNetworkTreeItemModel[];
|
|
11
10
|
readonly displayName: string;
|
|
11
|
+
readonly downloadFileName?: string;
|
|
12
12
|
readonly iconSuggestion?: string;
|
|
13
13
|
readonly isNetwork: boolean;
|
|
14
14
|
readonly tags?: readonly string[];
|
|
15
15
|
readonly temporaryNetworkExpirationTime?: Date;
|
|
16
|
-
readonly
|
|
16
|
+
readonly temporaryNetworkHocon?: string | null;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Recursively searches for a tree item with the specified ID within the given list of tree items.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { cleanUpAgentName, removeTrailingUuid } from "
|
|
1
|
+
import { cleanUpAgentName, removeTrailingUuid, toDisplayName } from "../../../utils/AgentName.js";
|
|
2
|
+
import { toSafeFilename } from "../../../utils/File.js";
|
|
2
3
|
//#endregion Types and Interfaces
|
|
3
4
|
/**
|
|
4
5
|
* Recursively searches for a tree item with the specified ID within the given list of tree items.
|
|
@@ -20,14 +21,6 @@ export const findTreeItemById = (items, itemId) => {
|
|
|
20
21
|
}
|
|
21
22
|
return undefined;
|
|
22
23
|
};
|
|
23
|
-
/**
|
|
24
|
-
* Converts a raw agent name into a display name for the tree view, respecting the user's preference for native
|
|
25
|
-
* vs cleaned names.
|
|
26
|
-
* @param itemName - The raw agent name from the API
|
|
27
|
-
* @param useNativeNames - Whether to use native names or cleaned-up names for display
|
|
28
|
-
* @returns The display name to show in the tree view
|
|
29
|
-
*/
|
|
30
|
-
const toDisplayName = (itemName, useNativeNames) => useNativeNames ? itemName : cleanUpAgentName(removeTrailingUuid(itemName));
|
|
31
24
|
/**
|
|
32
25
|
* Computes the display name for a network (leaf) node.
|
|
33
26
|
* @param label - The label to use for the tree item (usually derived from the agent name)
|
|
@@ -45,6 +38,14 @@ const toLeafDisplayName = (label, useNativeNames, displayNameOverride) => {
|
|
|
45
38
|
const cleanedName = cleanUpAgentName(displayNameOverride ?? removeTrailingUuid(label));
|
|
46
39
|
return cleanedName;
|
|
47
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Computes the filename used when exporting a network's HOCON to disk. The trailing reservation
|
|
43
|
+
* UUID is stripped first so the export carries a clean name (toSafeFilename would otherwise flatten
|
|
44
|
+
* the UUID's hyphens to underscores).
|
|
45
|
+
* @param label - The label to use for the tree item (usually derived from the agent name)
|
|
46
|
+
* @returns The sanitized `.hocon` filename for the exported network HOCON
|
|
47
|
+
*/
|
|
48
|
+
const toDownloadFileName = (label) => `${toSafeFilename(removeTrailingUuid(label))}.hocon`;
|
|
48
49
|
/**
|
|
49
50
|
* Converts an AgentInfo object into a tree item model representing a network (leaf node).
|
|
50
51
|
* @param network - The AgentInfo object containing details about the network
|
|
@@ -57,11 +58,12 @@ const toNetworkLeaf = (network, label, useNativeNames, metadata = {}) => ({
|
|
|
57
58
|
id: network.agent_name,
|
|
58
59
|
label,
|
|
59
60
|
displayName: toLeafDisplayName(label, useNativeNames, metadata.displayNameOverride),
|
|
61
|
+
downloadFileName: metadata.temporaryNetworkHocon ? toDownloadFileName(label) : undefined,
|
|
60
62
|
iconSuggestion: metadata.iconSuggestion,
|
|
61
63
|
isNetwork: true,
|
|
62
64
|
tags: network.tags,
|
|
63
65
|
temporaryNetworkExpirationTime: metadata.temporaryNetworkExpirationTime,
|
|
64
|
-
|
|
66
|
+
temporaryNetworkHocon: metadata.temporaryNetworkHocon,
|
|
65
67
|
});
|
|
66
68
|
/**
|
|
67
69
|
* Recursively sort tree nodes and their children by display name
|
|
@@ -174,9 +176,7 @@ export const buildTreeViewItems = (useNativeNames, regularNetworks = [], tempora
|
|
|
174
176
|
tree = withNetworkAdded(tree, temporaryNetwork.agentInfo, useNativeNames, {
|
|
175
177
|
iconSuggestion: "HourglassTop",
|
|
176
178
|
temporaryNetworkExpirationTime: new Date(temporaryNetwork.reservation.expiration_time_in_seconds * 1000),
|
|
177
|
-
|
|
178
|
-
// the import modal reads back in).
|
|
179
|
-
temporaryNetworkDefinition: temporaryNetwork.agentNetworkDefinition,
|
|
179
|
+
temporaryNetworkHocon: temporaryNetwork.networkHocon,
|
|
180
180
|
displayNameOverride: temporaryNetwork.agentNetworkName,
|
|
181
181
|
});
|
|
182
182
|
}
|
|
@@ -65,22 +65,8 @@ export declare const mergeNetworks: (target: TemporaryNetwork[], incoming: Tempo
|
|
|
65
65
|
/** Logs and notifies about a save error. Suppresses AbortError (user-canceled). */
|
|
66
66
|
export declare const notifySaveError: (agentName: string, e: unknown) => void;
|
|
67
67
|
/**
|
|
68
|
-
* Streams a network definition through the network designer
|
|
69
|
-
*
|
|
70
|
-
*
|
|
68
|
+
* Streams a network definition through the network designer to obtain its reservation.
|
|
69
|
+
* Returns the single updated network as a one-element list (empty if the designer returned
|
|
70
|
+
* no reservation).
|
|
71
71
|
*/
|
|
72
72
|
export declare const streamNetworkDesignerUpsert: (neuroSanURL: string, signal: AbortSignal, frontman: string, networkDef: AgentNetworkDefinitionEntry[], agentNetworkName: string | undefined, username: string) => Promise<TemporaryNetwork[]>;
|
|
73
|
-
/** Reasons an import can fail before its networks reach the store. */
|
|
74
|
-
export type ImportFailureReason = "invalid-definition" | "no-reservation";
|
|
75
|
-
export type ImportNetworkResult = {
|
|
76
|
-
networks: TemporaryNetwork[];
|
|
77
|
-
} | {
|
|
78
|
-
failure: ImportFailureReason;
|
|
79
|
-
};
|
|
80
|
-
export declare const IMPORT_FAILURE_DETAIL: Record<ImportFailureReason, string>;
|
|
81
|
-
/**
|
|
82
|
-
* Converts imported JSON into a network definition and streams it through the
|
|
83
|
-
* network designer to obtain reservations. Returns the resulting networks, or a
|
|
84
|
-
* failure reason if the content is not a valid definition or no reservation is returned.
|
|
85
|
-
*/
|
|
86
|
-
export declare const importNetworkFromJson: (content: string, agentNetworkName: string, neuroSanURL: string, username: string) => Promise<ImportNetworkResult>;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { keyBy, mergeWith } from "lodash-es";
|
|
2
2
|
import { AGENT_NETWORK_DEFINITION_KEY, AGENT_NETWORK_HOCON, AGENT_RESERVATIONS_KEY, DisplayAs, TEMPORARY_NETWORK_FOLDER, } from "./const.js";
|
|
3
|
-
import { jsonToNetworkDefinition } from "./Sidebar/ImportNetworkModal.js";
|
|
4
3
|
import { sendNetworkDesignerRequest } from "../../controller/agent/Agent.js";
|
|
5
4
|
import { ChatMessageType } from "../../generated/neuro-san/NeuroSanClient.js";
|
|
6
|
-
import {
|
|
5
|
+
import { removeTrailingUuid } from "../../utils/AgentName.js";
|
|
6
|
+
import { chatMessageFromChunk } from "../AgentChat/Common/Utils.js";
|
|
7
7
|
import { NotificationType, sendNotification } from "../Common/notification.js";
|
|
8
|
+
//#endregion: Types
|
|
8
9
|
/**
|
|
9
10
|
* Extracts agent reservations from a chat message, if they exist.
|
|
10
11
|
* @param message The chat message to extract reservations from. We expect reservations to be present in messages of
|
|
@@ -90,22 +91,17 @@ export const isTemporaryNetwork = (agentName, networks) => agentName !== null &&
|
|
|
90
91
|
* Merges incoming networks into target, keeping the entry with the highest expiration time.
|
|
91
92
|
* Returns a new array; does not mutate either argument.
|
|
92
93
|
*/
|
|
93
|
-
export const mergeNetworks = (target, incoming) =>
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (n.reservation.expiration_time_in_seconds > result[existingIdx].reservation.expiration_time_in_seconds) {
|
|
100
|
-
return result.map((e, i) => (i === existingIdx ? n : e));
|
|
101
|
-
}
|
|
102
|
-
return result;
|
|
103
|
-
}, [...target]);
|
|
94
|
+
export const mergeNetworks = (target, incoming) => Object.values(mergeWith(keyBy(target, "agentNetworkName"), keyBy(incoming, "agentNetworkName"),
|
|
95
|
+
// Both collections share a name: keep whichever reservation expires later, existing wins ties.
|
|
96
|
+
(existing, candidate) => existing &&
|
|
97
|
+
existing.reservation.expiration_time_in_seconds >= candidate.reservation.expiration_time_in_seconds
|
|
98
|
+
? existing
|
|
99
|
+
: candidate));
|
|
104
100
|
/**
|
|
105
101
|
* Extracts TemporaryNetworks from a single streamed chunk, merging into `accumulated`.
|
|
106
102
|
* Returns `accumulated` unchanged if the chunk yields no reservations or on parse error.
|
|
107
103
|
*/
|
|
108
|
-
const
|
|
104
|
+
const collectNetworkFromChunk = (chunk, updated, accumulated) => {
|
|
109
105
|
try {
|
|
110
106
|
const chatMessage = chatMessageFromChunk(chunk);
|
|
111
107
|
if (!chatMessage)
|
|
@@ -132,35 +128,16 @@ export const notifySaveError = (agentName, e) => {
|
|
|
132
128
|
sendNotification(NotificationType.error, `Failed to update network "${agentName}".`, detail);
|
|
133
129
|
};
|
|
134
130
|
/**
|
|
135
|
-
* Streams a network definition through the network designer
|
|
136
|
-
*
|
|
137
|
-
*
|
|
131
|
+
* Streams a network definition through the network designer to obtain its reservation.
|
|
132
|
+
* Returns the single updated network as a one-element list (empty if the designer returned
|
|
133
|
+
* no reservation).
|
|
138
134
|
*/
|
|
139
135
|
export const streamNetworkDesignerUpsert = async (neuroSanURL, signal, frontman, networkDef, agentNetworkName, username) => {
|
|
140
136
|
let newNetworks = [];
|
|
141
137
|
await sendNetworkDesignerRequest(neuroSanURL, signal, frontman, networkDef, agentNetworkName, username, (chunk) => {
|
|
142
|
-
|
|
138
|
+
// There is only one network. The designer echoes it across streamed chunks. Merge by name so the
|
|
139
|
+
// repeated echoes collapse into that single entry rather than appending duplicates.
|
|
140
|
+
newNetworks = collectNetworkFromChunk(chunk, networkDef, newNetworks);
|
|
143
141
|
});
|
|
144
142
|
return newNetworks;
|
|
145
143
|
};
|
|
146
|
-
export const IMPORT_FAILURE_DETAIL = {
|
|
147
|
-
"invalid-definition": "The file does not contain a valid network definition.",
|
|
148
|
-
"no-reservation": "The network designer did not return a reservation. Please try again.",
|
|
149
|
-
};
|
|
150
|
-
/**
|
|
151
|
-
* Converts imported JSON into a network definition and streams it through the
|
|
152
|
-
* network designer to obtain reservations. Returns the resulting networks, or a
|
|
153
|
-
* failure reason if the content is not a valid definition or no reservation is returned.
|
|
154
|
-
*/
|
|
155
|
-
export const importNetworkFromJson = async (content, agentNetworkName, neuroSanURL, username) => {
|
|
156
|
-
const networkDef = jsonToNetworkDefinition(JSON.parse(content));
|
|
157
|
-
if (networkDef.length === 0) {
|
|
158
|
-
return { failure: "invalid-definition" };
|
|
159
|
-
}
|
|
160
|
-
const frontman = getFrontman(networkDef)?.origin ?? networkDef[0]?.origin ?? "agent";
|
|
161
|
-
const networks = await streamNetworkDesignerUpsert(neuroSanURL, new AbortController().signal, frontman, networkDef, agentNetworkName, username);
|
|
162
|
-
if (networks.length === 0) {
|
|
163
|
-
return { failure: "no-reservation" };
|
|
164
|
-
}
|
|
165
|
-
return { networks };
|
|
166
|
-
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
2
|
/**
|
|
2
3
|
* This file defines the steps for the main tour of the Multi-Agent Accelerator application.
|
|
3
4
|
*
|
|
@@ -18,8 +19,7 @@ export const MAIN_TOUR_STEPS = [
|
|
|
18
19
|
placement: "bottom",
|
|
19
20
|
},
|
|
20
21
|
{
|
|
21
|
-
content: "Agent Network Designer: Click here to create and edit your own network, with the help of a "
|
|
22
|
-
"powerful AI assistant.",
|
|
22
|
+
content: (_jsxs(_Fragment, { children: ["Agent Network Designer: Click here to create and edit your own network, with the help of a powerful AI assistant.", _jsx("br", {}), _jsx("br", {}), "Networks you create can be downloaded from the sidebar as a HOCON file and run in neuro-san or neuro-san-studio. See the User Guide (under Help) for more information."] })),
|
|
23
23
|
target: () => document.querySelector("#add-network-icon"),
|
|
24
24
|
placement: "bottom",
|
|
25
25
|
},
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import { ConnectivityInfo } from "../../generated/neuro-san/NeuroSanClient.js";
|
|
2
|
-
export declare const DEFAULT_FRONTMAN_X_POS = 150;
|
|
3
|
-
export declare const DEFAULT_FRONTMAN_Y_POS = 450;
|
|
4
|
-
export declare const BASE_RADIUS = 100;
|
|
5
|
-
export declare const LEVEL_SPACING = 150;
|
|
6
|
-
export declare const TEMPORARY_NETWORK_FOLDER = "temporary";
|
|
7
|
-
export declare const AGENT_RESERVATIONS_KEY = "agent_reservations";
|
|
8
|
-
export declare const AGENT_NETWORK_HOCON = "agent_network_hocon_text";
|
|
9
|
-
export declare const AGENT_PROGRESS_CONNECTIVITY_KEY = "connectivity_info";
|
|
10
|
-
export declare const AGENT_NETWORK_DESIGNER_ID = "agent_network_designer";
|
|
11
2
|
export declare const AGENT_NETWORK_DEFINITION_KEY = "agent_network_definition";
|
|
3
|
+
export declare const AGENT_NETWORK_DESIGNER_ID = "agent_network_designer";
|
|
4
|
+
export declare const AGENT_NETWORK_HOCON = "agent_network_hocon_text";
|
|
12
5
|
export declare const AGENT_NETWORK_NAME_KEY = "agent_network_name";
|
|
13
|
-
export declare const
|
|
6
|
+
export declare const AGENT_PROGRESS_CONNECTIVITY_KEY = "connectivity_info";
|
|
7
|
+
export declare const AGENT_RESERVATIONS_KEY = "agent_reservations";
|
|
14
8
|
/**
|
|
15
9
|
* A single agent entry within an agent network definition, as received in sly_data from the backend.
|
|
16
10
|
* Extends ConnectivityInfo with editable instructions and description fields for the Agent Network Designer.
|
|
@@ -19,6 +13,9 @@ export type AgentNetworkDefinitionEntry = ConnectivityInfo & {
|
|
|
19
13
|
readonly instructions?: string;
|
|
20
14
|
readonly description?: string;
|
|
21
15
|
};
|
|
16
|
+
export declare const BASE_RADIUS = 100;
|
|
17
|
+
export declare const DEFAULT_FRONTMAN_X_POS = 150;
|
|
18
|
+
export declare const DEFAULT_FRONTMAN_Y_POS = 450;
|
|
22
19
|
/** Possible values for the `display_as` field in ConnectivityInfo / AgentNetworkDefinitionEntry. */
|
|
23
20
|
export declare enum DisplayAs {
|
|
24
21
|
LLM_AGENT = "llm_agent",
|
|
@@ -26,6 +23,9 @@ export declare enum DisplayAs {
|
|
|
26
23
|
LANGCHAIN_TOOL = "langchain_tool",
|
|
27
24
|
EXTERNAL_AGENT = "external_agent"
|
|
28
25
|
}
|
|
26
|
+
export declare const EXPIRED_NETWORKS_CHECK_INTERVAL_MS: number;
|
|
29
27
|
export declare const GRACE_PERIOD_MS: number;
|
|
28
|
+
export declare const LEVEL_SPACING = 150;
|
|
30
29
|
export declare const SHOW_TOUR_DELAY_MS = 5000;
|
|
31
|
-
export declare const
|
|
30
|
+
export declare const TEMPORARY_NETWORK_FOLDER = "temporary";
|
|
31
|
+
export declare const TRIGGER_APP_TOUR_EVENT_NAME = "trigger-app-tour";
|
|
@@ -13,30 +13,22 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
export const DEFAULT_FRONTMAN_X_POS = 150;
|
|
17
|
-
export const DEFAULT_FRONTMAN_Y_POS = 450;
|
|
18
|
-
// Minimum distance from center
|
|
19
|
-
export const BASE_RADIUS = 100;
|
|
20
|
-
// Distance between depth levels
|
|
21
|
-
export const LEVEL_SPACING = 150;
|
|
22
|
-
// Temporary folder name for networks created from agent reservations. These networks are not "in a folder" when
|
|
23
|
-
// they come from the backend, but we need to put them somewhere in the UI, and this makes it clear that they're
|
|
24
|
-
// temporary.
|
|
25
|
-
export const TEMPORARY_NETWORK_FOLDER = "temporary";
|
|
26
|
-
// We expect the agent reservations to be stored in sly_data under this key
|
|
27
|
-
export const AGENT_RESERVATIONS_KEY = "agent_reservations";
|
|
28
|
-
// We expect the agent network HOCON to be stored in sly_data under this key, if it is provided by the backend
|
|
29
|
-
export const AGENT_NETWORK_HOCON = "agent_network_hocon_text";
|
|
30
|
-
// The key in the message structure where connectivity info is stored for agent progress messages
|
|
31
|
-
export const AGENT_PROGRESS_CONNECTIVITY_KEY = "connectivity_info";
|
|
32
|
-
// Agent name for the special "Agent Network Designer" network
|
|
33
|
-
export const AGENT_NETWORK_DESIGNER_ID = "agent_network_designer";
|
|
34
16
|
// The key in sly_data where the agent network definition is stored
|
|
35
17
|
export const AGENT_NETWORK_DEFINITION_KEY = "agent_network_definition";
|
|
18
|
+
// Agent name for the special "Agent Network Designer" network
|
|
19
|
+
export const AGENT_NETWORK_DESIGNER_ID = "agent_network_designer";
|
|
20
|
+
// We expect the agent network HOCON to be stored in sly_data under this key, if it is provided by the backend
|
|
21
|
+
export const AGENT_NETWORK_HOCON = "agent_network_hocon_text";
|
|
36
22
|
// The key in sly_data where the agent network name is stored
|
|
37
23
|
export const AGENT_NETWORK_NAME_KEY = "agent_network_name";
|
|
38
|
-
// The
|
|
39
|
-
export const
|
|
24
|
+
// The key in the message structure where connectivity info is stored for agent progress messages
|
|
25
|
+
export const AGENT_PROGRESS_CONNECTIVITY_KEY = "connectivity_info";
|
|
26
|
+
// We expect the agent reservations to be stored in sly_data under this key
|
|
27
|
+
export const AGENT_RESERVATIONS_KEY = "agent_reservations";
|
|
28
|
+
// Minimum distance from center
|
|
29
|
+
export const BASE_RADIUS = 100;
|
|
30
|
+
export const DEFAULT_FRONTMAN_X_POS = 150;
|
|
31
|
+
export const DEFAULT_FRONTMAN_Y_POS = 450;
|
|
40
32
|
/** Possible values for the `display_as` field in ConnectivityInfo / AgentNetworkDefinitionEntry. */
|
|
41
33
|
export var DisplayAs;
|
|
42
34
|
(function (DisplayAs) {
|
|
@@ -45,9 +37,17 @@ export var DisplayAs;
|
|
|
45
37
|
DisplayAs["LANGCHAIN_TOOL"] = "langchain_tool";
|
|
46
38
|
DisplayAs["EXTERNAL_AGENT"] = "external_agent";
|
|
47
39
|
})(DisplayAs || (DisplayAs = {}));
|
|
40
|
+
// Check for expired networks every this many milliseconds
|
|
41
|
+
export const EXPIRED_NETWORKS_CHECK_INTERVAL_MS = 10 * 1000;
|
|
48
42
|
// Display expired temporary networks for this amount of time after they expire so users can see what happened
|
|
49
43
|
export const GRACE_PERIOD_MS = 5 * 60 * 1000; // 5 minutes
|
|
44
|
+
// Distance between depth levels
|
|
45
|
+
export const LEVEL_SPACING = 150;
|
|
50
46
|
// We show the tour modal after this amount of time so as not to "pounce" on the user when they first open the app
|
|
51
47
|
export const SHOW_TOUR_DELAY_MS = 5000;
|
|
52
|
-
//
|
|
53
|
-
|
|
48
|
+
// Temporary folder name for networks created from agent reservations. These networks are not "in a folder" when
|
|
49
|
+
// they come from the backend, but we need to put them somewhere in the UI, and this makes it clear that they're
|
|
50
|
+
// temporary.
|
|
51
|
+
export const TEMPORARY_NETWORK_FOLDER = "temporary";
|
|
52
|
+
// The event name that needs to be fired for the app tour to start
|
|
53
|
+
export const TRIGGER_APP_TOUR_EVENT_NAME = "trigger-app-tour";
|
|
@@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
import { keyBy } from "lodash-es";
|
|
16
17
|
import { create } from "zustand";
|
|
17
18
|
import { persist } from "zustand/middleware";
|
|
18
19
|
/**
|
|
@@ -22,29 +23,19 @@ export const useTempNetworksStore = create()(persist((set) => ({
|
|
|
22
23
|
tempNetworks: [],
|
|
23
24
|
setTempNetworks: (tempNetworks) => set({ tempNetworks }),
|
|
24
25
|
upsertTempNetworks: (incomingNetworks) => {
|
|
25
|
-
set((state) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
updated.push(incomingNetwork); // no existing entry — add as new
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return { tempNetworks: updated };
|
|
37
|
-
});
|
|
26
|
+
set((state) => ({
|
|
27
|
+
// Key both sides by name and let incoming win; existing entries keep their position,
|
|
28
|
+
// new ones are appended.
|
|
29
|
+
tempNetworks: Object.values({
|
|
30
|
+
...keyBy(state.tempNetworks, "agentNetworkName"),
|
|
31
|
+
...keyBy(incomingNetworks, "agentNetworkName"),
|
|
32
|
+
}),
|
|
33
|
+
}));
|
|
38
34
|
return incomingNetworks;
|
|
39
35
|
},
|
|
40
|
-
updateTempNetworkDefinition: (networkName, agentNetworkDefinition) => set((
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (existingIndex >= 0) {
|
|
44
|
-
updated[existingIndex] = { ...updated[existingIndex], agentNetworkDefinition };
|
|
45
|
-
}
|
|
46
|
-
return { tempNetworks: updated };
|
|
47
|
-
}),
|
|
36
|
+
updateTempNetworkDefinition: (networkName, agentNetworkDefinition) => set(({ tempNetworks }) => ({
|
|
37
|
+
tempNetworks: tempNetworks.map((network) => network.agentInfo.agent_name === networkName ? { ...network, agentNetworkDefinition } : network),
|
|
38
|
+
})),
|
|
48
39
|
}), {
|
|
49
40
|
name: "temp-networks",
|
|
50
41
|
}));
|