@cognizant-ai-lab/ui-common 1.5.0 → 1.6.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/Theme/Theme.js +3 -3
- package/dist/components/AgentChat/ChatCommon/ChatCommon.d.ts +11 -1
- package/dist/components/AgentChat/ChatCommon/ChatCommon.js +284 -285
- package/dist/components/AgentChat/ChatCommon/ChatHistory.d.ts +1 -7
- package/dist/components/AgentChat/ChatCommon/ChatHistory.js +33 -22
- package/dist/components/AgentChat/ChatCommon/ControlButtons.js +2 -2
- package/dist/components/AgentChat/ChatCommon/Conversation.d.ts +13 -0
- package/dist/components/AgentChat/ChatCommon/Conversation.js +80 -0
- package/dist/components/AgentChat/ChatCommon/ConversationTurn.d.ts +23 -0
- package/dist/components/AgentChat/ChatCommon/ConversationTurn.js +11 -0
- package/dist/components/AgentChat/ChatCommon/FormattedMarkdown.js +5 -3
- package/dist/components/AgentChat/ChatCommon/SampleQueries.d.ts +3 -0
- package/dist/components/AgentChat/ChatCommon/SampleQueries.js +6 -3
- package/dist/components/AgentChat/ChatCommon/Thinking.d.ts +12 -0
- package/dist/components/AgentChat/ChatCommon/Thinking.js +51 -0
- package/dist/components/AgentChat/Common/LlmChatButton.d.ts +2 -2
- package/dist/components/AgentChat/Common/Types.d.ts +6 -5
- package/dist/components/AgentChat/Common/Types.js +5 -0
- package/dist/components/AgentChat/Common/Utils.d.ts +1 -1
- package/dist/components/AgentChat/Common/Utils.js +14 -9
- package/dist/components/Common/AccordionLite.d.ts +14 -0
- package/dist/components/Common/AccordionLite.js +25 -0
- package/dist/components/Common/ConfirmationModal.d.ts +1 -0
- package/dist/components/Common/ConfirmationModal.js +1 -1
- package/dist/components/Common/CustomerLogo.js +1 -1
- package/dist/components/Common/MUIAlert.d.ts +1 -0
- package/dist/components/Common/MUIAlert.js +3 -4
- package/dist/components/Common/Navbar.d.ts +2 -1
- package/dist/components/Common/Navbar.js +8 -4
- package/dist/components/Common/notification.d.ts +1 -1
- package/dist/components/Common/notification.js +17 -12
- package/dist/components/MultiAgentAccelerator/AgentFlow.d.ts +8 -0
- package/dist/components/MultiAgentAccelerator/AgentFlow.js +282 -82
- package/dist/components/MultiAgentAccelerator/AgentNode.d.ts +3 -1
- package/dist/components/MultiAgentAccelerator/AgentNode.js +64 -28
- package/dist/components/MultiAgentAccelerator/AgentNodePopup.d.ts +1 -4
- package/dist/components/MultiAgentAccelerator/AgentNodePopup.js +4 -5
- package/dist/components/MultiAgentAccelerator/GraphLayouts.js +19 -9
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.d.ts +2 -2
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +268 -60
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.d.ts +1 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.js +28 -12
- package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.d.ts +1 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.js +21 -5
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.d.ts +4 -3
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.js +8 -2
- package/dist/components/MultiAgentAccelerator/TemporaryNetworks.d.ts +19 -2
- package/dist/components/MultiAgentAccelerator/TemporaryNetworks.js +40 -5
- package/dist/components/MultiAgentAccelerator/ThoughtBubbleOverlay.js +27 -14
- package/dist/components/MultiAgentAccelerator/Tour/MainTourSteps.d.ts +7 -0
- package/dist/components/MultiAgentAccelerator/Tour/MainTourSteps.js +88 -0
- package/dist/components/MultiAgentAccelerator/const.d.ts +7 -10
- package/dist/components/MultiAgentAccelerator/const.js +9 -10
- package/dist/const.d.ts +5 -1
- package/dist/const.js +5 -2
- package/dist/controller/agent/Agent.d.ts +10 -0
- package/dist/controller/agent/Agent.js +17 -1
- package/dist/controller/llm/LlmChat.js +2 -2
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/state/TemporaryNetworks.d.ts +5 -15
- package/dist/state/TemporaryNetworks.js +15 -34
- package/dist/state/Tour.d.ts +29 -0
- package/dist/state/Tour.js +22 -0
- package/dist/state/UserInfo.d.ts +2 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/Authentication.js +12 -3
- package/dist/utils/File.d.ts +7 -0
- package/dist/utils/File.js +14 -3
- package/dist/utils/text.js +2 -2
- package/dist/utils/title.js +1 -1
- package/dist/utils/zIndexLayers.js +3 -0
- package/package.json +15 -11
- package/dist/components/AgentChat/ChatCommon/AgentConnectivity.d.ts +0 -14
- package/dist/components/AgentChat/ChatCommon/AgentConnectivity.js +0 -23
- package/dist/components/AgentChat/ChatCommon/Greetings.d.ts +0 -1
- package/dist/components/AgentChat/ChatCommon/Greetings.js +0 -38
- package/dist/components/AgentChat/ChatCommon/UserQueryDisplay.d.ts +0 -7
- package/dist/components/AgentChat/ChatCommon/UserQueryDisplay.js +0 -32
- package/dist/components/Common/LlmChatOptionsButton.d.ts +0 -6
- package/dist/components/Common/LlmChatOptionsButton.js +0 -31
|
@@ -22,23 +22,29 @@ import { useTheme } from "@mui/material/styles";
|
|
|
22
22
|
import Typography from "@mui/material/Typography";
|
|
23
23
|
import { ReactFlowProvider } from "@xyflow/react";
|
|
24
24
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
25
|
+
import { useJoyride } from "react-joyride";
|
|
25
26
|
import { extractConversations } from "./AgentConversations.js";
|
|
26
27
|
import { getUpdatedAgentCounts } from "./AgentCounts.js";
|
|
27
28
|
import { AgentFlow } from "./AgentFlow.js";
|
|
28
29
|
import { extractAgentNetworkDesignerProgress } from "./AgentNetworkDesigner.js";
|
|
29
|
-
import { AGENT_NETWORK_DEFINITION_KEY, AGENT_NETWORK_DESIGNER_ID, AGENT_NETWORK_HOCON, AGENT_NETWORK_NAME_KEY, } from "./const.js";
|
|
30
|
+
import { AGENT_NETWORK_DEFINITION_KEY, AGENT_NETWORK_DESIGNER_ID, AGENT_NETWORK_HOCON, AGENT_NETWORK_NAME_KEY, TRIGGER_APP_TOUR_EVENT_NAME, } from "./const.js";
|
|
30
31
|
import { Sidebar } from "./Sidebar/Sidebar.js";
|
|
31
|
-
import {
|
|
32
|
-
import { getAgentIconSuggestions, getAgentNetworks, getConnectivity, getNetworkIconSuggestions, } from "../../controller/agent/Agent.js";
|
|
32
|
+
import { extractTemporaryNetworksFromMessage, isTemporaryNetwork, mergeNetworks } from "./TemporaryNetworks.js";
|
|
33
|
+
import { getAgentFunction, getAgentIconSuggestions, getAgentNetworks, getConnectivity, getNetworkIconSuggestions, sendNetworkDesignerUpdate, } from "../../controller/agent/Agent.js";
|
|
34
|
+
import { useAgentChatHistoryStore } from "../../state/ChatHistory.js";
|
|
33
35
|
import { useSettingsStore } from "../../state/Settings.js";
|
|
34
36
|
import { useTempNetworksStore } from "../../state/TemporaryNetworks.js";
|
|
37
|
+
import { TourPromptState, useTourStore } from "../../state/Tour.js";
|
|
35
38
|
import { useLocalStorage } from "../../utils/useLocalStorage.js";
|
|
36
39
|
import { getZIndex } from "../../utils/zIndexLayers.js";
|
|
37
40
|
import { ChatCommon } from "../AgentChat/ChatCommon/ChatCommon.js";
|
|
38
41
|
import { SmallLlmChatButton } from "../AgentChat/Common/LlmChatButton.js";
|
|
42
|
+
import { isLegacyAgentType } from "../AgentChat/Common/Types.js";
|
|
39
43
|
import { chatMessageFromChunk, cleanUpAgentName, removeTrailingUuid } from "../AgentChat/Common/Utils.js";
|
|
40
|
-
import { ConfirmationModal } from "../Common/ConfirmationModal.js";
|
|
44
|
+
import { ConfirmationModal, StyledButton } from "../Common/ConfirmationModal.js";
|
|
41
45
|
import { closeNotification, NotificationType, sendNotification } from "../Common/notification.js";
|
|
46
|
+
import { MAIN_TOUR_STEPS } from "./Tour/MainTourSteps.js";
|
|
47
|
+
import { MUIDialog } from "../Common/MUIDialog.js";
|
|
42
48
|
// Check for expired networks every this many milliseconds
|
|
43
49
|
const EXPIRED_NETWORKS_CHECK_INTERVAL_MS = 10 * 1000;
|
|
44
50
|
// Display expired temporary networks for this amount of time after they expire so users can see what happened
|
|
@@ -47,6 +53,40 @@ export const GRACE_PERIOD_MS = 5 * 60 * 1000; // 5 minutes
|
|
|
47
53
|
const GROW_ANIMATION_TIME_MS = 800;
|
|
48
54
|
// Optimization to avoid creating a new empty map on every render
|
|
49
55
|
const EMPTY_THOUGHT_BUBBLE_EDGES = new Map();
|
|
56
|
+
// We show the tour modal after this amount of time so as not to "pounce" on the user when they first open the app
|
|
57
|
+
export const SHOW_TOUR_DELAY_MS = 5000;
|
|
58
|
+
// #region: Agent-save helpers
|
|
59
|
+
/**
|
|
60
|
+
* Extracts TemporaryNetworks from a single streamed chunk, merging into `accumulated`.
|
|
61
|
+
* Returns `accumulated` unchanged if the chunk yields no reservations or on parse error.
|
|
62
|
+
*/
|
|
63
|
+
const collectNetworksFromChunk = (chunk, updated, accumulated) => {
|
|
64
|
+
try {
|
|
65
|
+
const chatMessage = chatMessageFromChunk(chunk);
|
|
66
|
+
if (!chatMessage)
|
|
67
|
+
return accumulated;
|
|
68
|
+
// Always use the user's edited definition as the authoritative value.
|
|
69
|
+
const converted = extractTemporaryNetworksFromMessage(chatMessage, updated);
|
|
70
|
+
if (converted.length === 0)
|
|
71
|
+
return accumulated;
|
|
72
|
+
return mergeNetworks(accumulated, converted);
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
console.warn("Failed to process chunk from network designer:", e);
|
|
76
|
+
return accumulated;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
/** Logs and notifies about a save error. Suppresses AbortError (user-cancelled). */
|
|
80
|
+
const notifySaveError = (agentName, e) => {
|
|
81
|
+
if (e instanceof DOMException && e.name === "AbortError")
|
|
82
|
+
return;
|
|
83
|
+
console.error("Failed to submit agent network update:", e);
|
|
84
|
+
const detail = e instanceof DOMException && e.name === "TimeoutError"
|
|
85
|
+
? "The request timed out waiting for the server. Please try again."
|
|
86
|
+
: String(e);
|
|
87
|
+
sendNotification(NotificationType.error, `Failed to update network "${agentName}".`, detail);
|
|
88
|
+
};
|
|
89
|
+
// #endregion: Agent-save helpers
|
|
50
90
|
/**
|
|
51
91
|
* Main Multi-Agent Accelerator component that contains the sidebar, agent flow, and chat components.
|
|
52
92
|
* @param backendNeuroSanApiUrl Initial URL of the backend Neuro-San API. User can change this in the UI.
|
|
@@ -59,6 +99,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
59
99
|
const enableZenMode = useSettingsStore((state) => state.settings.behavior.enableZenMode);
|
|
60
100
|
// Stores whether are currently awaiting LLM response (for knowing when to show spinners)
|
|
61
101
|
const [isAwaitingLlm, setIsAwaitingLlm] = useState(false);
|
|
102
|
+
const [isEditingNetwork, setIsEditingNetwork] = useState(false);
|
|
62
103
|
// Track streaming state - controls thought bubble cleanup timer, and enables "zen mode" (hides outer panels after
|
|
63
104
|
// animation)
|
|
64
105
|
const [isStreaming, setIsStreaming] = useState(false);
|
|
@@ -69,23 +110,32 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
69
110
|
const [newlyAddedTemporaryNetworks, setNewlyAddedTemporaryNetworks] = useState(new Set());
|
|
70
111
|
const [networkIconSuggestions, setNetworkIconSuggestions] = useState({});
|
|
71
112
|
const [agentsInNetwork, setAgentsInNetwork] = useState([]);
|
|
113
|
+
const [sampleQueries, setSampleQueries] = useState([]);
|
|
72
114
|
// Agents in network under construction by Agent Network Designer -
|
|
73
115
|
// updated in real time as we receive progress messages from the backend.
|
|
74
116
|
const [agentsInNetworkDesigner, setAgentsInNetworkDesigner] = useState([]);
|
|
75
117
|
const [agentIconSuggestions, setAgentIconSuggestions] = useState(null);
|
|
76
118
|
const [selectedNetwork, setSelectedNetwork] = useState(null);
|
|
119
|
+
const [networkDescription, setNetworkDescription] = useState("");
|
|
77
120
|
const networkDisplayName = useMemo(() => cleanUpAgentName(removeTrailingUuid(selectedNetwork)), [selectedNetwork]);
|
|
78
|
-
// Track whether we've shown the info popup so we don't keep bugging the user with it
|
|
79
|
-
const [haveShownPopup, setHaveShownPopup] = useState(false);
|
|
80
121
|
const [customURLLocalStorage, setCustomURLLocalStorage] = useLocalStorage("customAgentNetworkURL", null);
|
|
81
122
|
// An extra set of quotes is making it in the string in local storage.
|
|
82
123
|
const [neuroSanURL, setNeuroSanURL] = useState(customURLLocalStorage?.replaceAll('"', "") || backendNeuroSanApiUrl);
|
|
83
|
-
|
|
124
|
+
// Tracks how many times each agent has been involved in the conversation
|
|
125
|
+
const [agentCounts, setAgentCounts] = useState(new Map());
|
|
126
|
+
//common function to change the selected network and reset related state
|
|
127
|
+
const changeSelectedNetwork = useCallback((next) => {
|
|
128
|
+
setSelectedNetwork(next);
|
|
129
|
+
setAgentCounts(new Map());
|
|
130
|
+
}, []);
|
|
84
131
|
const conversationsRef = useRef(null);
|
|
85
132
|
const [currentConversations, setCurrentConversations] = useState([]);
|
|
86
133
|
const [networkToBeDeleted, setNetworkToBeDeleted] = useState(null);
|
|
87
134
|
// State to hold thought bubble edges - avoids duplicates across layout recalculations
|
|
88
135
|
const [thoughtBubbleEdges, setThoughtBubbleEdges] = useState(new Map());
|
|
136
|
+
const [confirmationModalOpen, setConfirmationModalOpen] = useState(false);
|
|
137
|
+
const [tourModalOpen, setTourModalOpen] = useState(false);
|
|
138
|
+
const [haveShownTourModal, setHaveShownTourModal] = useState(false);
|
|
89
139
|
const customURLCallback = useCallback((url) => {
|
|
90
140
|
setNeuroSanURL(url || backendNeuroSanApiUrl);
|
|
91
141
|
setCustomURLLocalStorage(url === "" ? null : url);
|
|
@@ -96,31 +146,75 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
96
146
|
.map((agent) => agent.origin)
|
|
97
147
|
.sort()
|
|
98
148
|
.join(","), [agentsInNetwork]);
|
|
149
|
+
// Introductory tour
|
|
150
|
+
// Track that the user requested the tour, and we should start it once network data is available
|
|
151
|
+
const [tourRequested, setTourRequested] = useState(false);
|
|
152
|
+
// Tour persisted status
|
|
153
|
+
const tourStatus = useTourStore((s) => s.status);
|
|
154
|
+
const setTourStatus = useTourStore((s) => s.setStatus);
|
|
155
|
+
const { controls, Tour } = useJoyride({
|
|
156
|
+
continuous: true,
|
|
157
|
+
steps: MAIN_TOUR_STEPS,
|
|
158
|
+
options: {
|
|
159
|
+
buttons: ["back", "close", "primary", "skip"],
|
|
160
|
+
backgroundColor: "var(--bs-secondary)",
|
|
161
|
+
textColor: "var(--bs-white)",
|
|
162
|
+
primaryColor: "var(--bs-accent3-medium)",
|
|
163
|
+
arrowColor: "var(--bs-secondary)",
|
|
164
|
+
overlayColor: "rgba(var(--bs-primary-rgb), 0.82)",
|
|
165
|
+
showProgress: true,
|
|
166
|
+
zIndex: getZIndex(3, theme),
|
|
167
|
+
skipBeacon: true,
|
|
168
|
+
skipScroll: true,
|
|
169
|
+
},
|
|
170
|
+
locale: {
|
|
171
|
+
last: "End Tour",
|
|
172
|
+
skip: "Exit Tour",
|
|
173
|
+
},
|
|
174
|
+
});
|
|
99
175
|
const resetState = useCallback(() => {
|
|
100
176
|
setThoughtBubbleEdges(new Map());
|
|
101
177
|
setIsStreaming(false);
|
|
102
178
|
}, []);
|
|
103
179
|
// Reference to the ChatCommon component to allow external stop button to call its handleStop method
|
|
104
180
|
const chatRef = useRef(null);
|
|
181
|
+
// Clear chat whenever the user navigates to the Agent Network Designer, so they start fresh each time
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
if (selectedNetwork === AGENT_NETWORK_DESIGNER_ID) {
|
|
184
|
+
chatRef.current?.handleClearChat();
|
|
185
|
+
}
|
|
186
|
+
}, [selectedNetwork]);
|
|
105
187
|
// Special mode of operation where user is using Agent Network Designer to create a new network
|
|
106
188
|
const isNetworkDesignerMode = selectedNetwork === AGENT_NETWORK_DESIGNER_ID;
|
|
107
189
|
// Whether the currently selected network is a temporary network (agent reservation)
|
|
108
|
-
const isSelectedNetworkTemporary = selectedNetwork
|
|
190
|
+
const isSelectedNetworkTemporary = isTemporaryNetwork(selectedNetwork, temporaryNetworks);
|
|
109
191
|
// For temp networks, agent_network_definition and agent_network_name live in localStorage (not IndexedDB slyData).
|
|
110
192
|
// Supply them as extraSlyData so ChatCommon bounces them back to the backend on every request.
|
|
111
193
|
const currentTempNetwork = isSelectedNetworkTemporary
|
|
112
194
|
? temporaryNetworks.find((n) => n.agentInfo.agent_name === selectedNetwork)
|
|
113
195
|
: undefined;
|
|
196
|
+
// For Agent Network Designer: the backend echoes agent_network_name into IndexedDB sly_data as the conversation
|
|
197
|
+
// progresses. We read it back here to find the matching temp network and override agent_network_definition in the
|
|
198
|
+
// outgoing request — leaving what's in IndexedDB untouched.
|
|
199
|
+
const designerSlyData = useAgentChatHistoryStore((state) => state.history[AGENT_NETWORK_DESIGNER_ID]?.slyData);
|
|
200
|
+
const designerNetworkName = isNetworkDesignerMode
|
|
201
|
+
? designerSlyData?.[AGENT_NETWORK_NAME_KEY]
|
|
202
|
+
: undefined;
|
|
203
|
+
const designerTempNetwork = designerNetworkName
|
|
204
|
+
? temporaryNetworks.find((n) => n.agentNetworkName === designerNetworkName)
|
|
205
|
+
: undefined;
|
|
114
206
|
const extraSlyData = currentTempNetwork
|
|
115
207
|
? {
|
|
116
208
|
[AGENT_NETWORK_DEFINITION_KEY]: currentTempNetwork.agentNetworkDefinition,
|
|
117
|
-
// Use the
|
|
209
|
+
// Use the agentNetworkName, not reservation_id
|
|
118
210
|
...(currentTempNetwork.agentNetworkName
|
|
119
211
|
? { [AGENT_NETWORK_NAME_KEY]: currentTempNetwork.agentNetworkName }
|
|
120
212
|
: {}),
|
|
121
213
|
...(currentTempNetwork.networkHocon ? { [AGENT_NETWORK_HOCON]: currentTempNetwork.networkHocon } : {}),
|
|
122
214
|
}
|
|
123
|
-
:
|
|
215
|
+
: designerTempNetwork
|
|
216
|
+
? { [AGENT_NETWORK_DEFINITION_KEY]: designerTempNetwork.agentNetworkDefinition }
|
|
217
|
+
: undefined;
|
|
124
218
|
// Handle external stop button click - stops streaming and exits zen mode
|
|
125
219
|
const handleExternalStop = useCallback(() => {
|
|
126
220
|
chatRef.current?.handleStop();
|
|
@@ -138,10 +232,27 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
138
232
|
sendNotification(NotificationType.error, "Connection error", `Unable to get list of Agent Networks. Verify that ${neuroSanURL} is a valid ` +
|
|
139
233
|
`Multi-Agent Accelerator Server. Error: ${e}.`);
|
|
140
234
|
setNetworks([]);
|
|
141
|
-
|
|
235
|
+
changeSelectedNetwork(null);
|
|
142
236
|
}
|
|
143
237
|
})();
|
|
144
|
-
}, [neuroSanURL]);
|
|
238
|
+
}, [neuroSanURL, changeSelectedNetwork]);
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
const fetchAgentDetails = async () => {
|
|
241
|
+
// It is a Neuro-san agent, so get the function and connectivity info
|
|
242
|
+
try {
|
|
243
|
+
const agentFunction = await getAgentFunction(neuroSanURL, selectedNetwork, userInfo.userName);
|
|
244
|
+
setNetworkDescription(agentFunction?.function?.description || "");
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
// Ignore. May be a legacy agent without a functional description in Neuro-san.
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
// Clear out existing
|
|
251
|
+
setNetworkDescription("");
|
|
252
|
+
if (selectedNetwork && !isLegacyAgentType(selectedNetwork)) {
|
|
253
|
+
void fetchAgentDetails();
|
|
254
|
+
}
|
|
255
|
+
}, [neuroSanURL, selectedNetwork, userInfo.userName]);
|
|
145
256
|
useEffect(() => {
|
|
146
257
|
;
|
|
147
258
|
(async () => {
|
|
@@ -163,10 +274,15 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
163
274
|
if (selectedNetwork) {
|
|
164
275
|
try {
|
|
165
276
|
const connectivity = await getConnectivity(neuroSanURL, selectedNetwork, userInfo.userName);
|
|
166
|
-
const agentsInNetworkSorted = connectivity.connectivity_info
|
|
167
|
-
.concat()
|
|
168
|
-
.sort((a, b) => a?.origin.localeCompare(b?.origin));
|
|
277
|
+
const agentsInNetworkSorted = [...connectivity.connectivity_info].sort((a, b) => a?.origin.localeCompare(b?.origin));
|
|
169
278
|
setAgentsInNetwork(agentsInNetworkSorted);
|
|
279
|
+
const sampleQueriesTmp = connectivity?.metadata?.["sample_queries"];
|
|
280
|
+
if (Array.isArray(sampleQueriesTmp)) {
|
|
281
|
+
setSampleQueries(sampleQueriesTmp);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
setSampleQueries([]);
|
|
285
|
+
}
|
|
170
286
|
setAgentIconSuggestions(null);
|
|
171
287
|
closeNotification();
|
|
172
288
|
}
|
|
@@ -222,22 +338,47 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
222
338
|
return undefined;
|
|
223
339
|
const interval = setInterval(() => {
|
|
224
340
|
const now = Date.now() / 1000; // convert to seconds since epoch
|
|
341
|
+
const reapCutoff = now - GRACE_PERIOD_MS / 1000;
|
|
225
342
|
const currentTemporaryNetworks = useTempNetworksStore.getState().tempNetworks;
|
|
226
|
-
//
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
343
|
+
// Networks past the grace period get fully purged: removed from the store AND have their
|
|
344
|
+
// chat history / sly_data cleared from IndexedDB
|
|
345
|
+
const survivingNetworks = [];
|
|
346
|
+
for (const network of currentTemporaryNetworks) {
|
|
347
|
+
if (network.reservation.expiration_time_in_seconds <= reapCutoff) {
|
|
348
|
+
// This network has been expired for more than the grace period, so purge it
|
|
349
|
+
useAgentChatHistoryStore.getState().resetHistory(network.agentInfo.agent_name);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
survivingNetworks.push(network);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
useTempNetworksStore.getState().setTempNetworks(survivingNetworks);
|
|
356
|
+
// If the selected network has expired on the server (not including our grace period), deselect it
|
|
357
|
+
const selectedHasExpired = currentTemporaryNetworks.some((network) => network.agentInfo.agent_name === selectedNetwork &&
|
|
358
|
+
network.reservation.expiration_time_in_seconds <= now);
|
|
359
|
+
if (selectedHasExpired) {
|
|
360
|
+
changeSelectedNetwork(null);
|
|
237
361
|
}
|
|
238
362
|
}, EXPIRED_NETWORKS_CHECK_INTERVAL_MS);
|
|
239
363
|
return () => clearInterval(interval);
|
|
240
|
-
}, [temporaryNetworks, selectedNetwork]);
|
|
364
|
+
}, [changeSelectedNetwork, temporaryNetworks, selectedNetwork]);
|
|
365
|
+
const dismissTourModal = () => {
|
|
366
|
+
setTourModalOpen(false);
|
|
367
|
+
setHaveShownTourModal(true);
|
|
368
|
+
};
|
|
369
|
+
const handleExternalTourRequest = useCallback(() => {
|
|
370
|
+
// If nothing is selected, prime the network selection first
|
|
371
|
+
if (selectedNetwork == null && networks?.length > 0) {
|
|
372
|
+
setSelectedNetwork(networks[0].agent_name);
|
|
373
|
+
}
|
|
374
|
+
// Close the modal if open
|
|
375
|
+
setTourModalOpen(false);
|
|
376
|
+
setTourRequested(true);
|
|
377
|
+
}, [networks, selectedNetwork]);
|
|
378
|
+
useEffect(() => {
|
|
379
|
+
window.addEventListener(TRIGGER_APP_TOUR_EVENT_NAME, handleExternalTourRequest);
|
|
380
|
+
return () => window.removeEventListener(TRIGGER_APP_TOUR_EVENT_NAME, handleExternalTourRequest);
|
|
381
|
+
}, [handleExternalTourRequest, networks, selectedNetwork]);
|
|
241
382
|
const onChunkReceived = useCallback((chunk) => {
|
|
242
383
|
// Extract ChatMessage structure
|
|
243
384
|
const chatMessage = chatMessageFromChunk(chunk);
|
|
@@ -250,8 +391,10 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
250
391
|
conversationsRef.current = result;
|
|
251
392
|
setCurrentConversations(result);
|
|
252
393
|
}
|
|
253
|
-
//
|
|
254
|
-
|
|
394
|
+
// Update agent hit counts
|
|
395
|
+
setAgentCounts((prevCounts) => {
|
|
396
|
+
return getUpdatedAgentCounts(prevCounts, chatMessage.origin);
|
|
397
|
+
});
|
|
255
398
|
// Agent network designer progress messages
|
|
256
399
|
if (isNetworkDesignerMode) {
|
|
257
400
|
const networkInProgress = extractAgentNetworkDesignerProgress(chatMessage);
|
|
@@ -259,16 +402,9 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
259
402
|
setAgentsInNetworkDesigner(networkInProgress);
|
|
260
403
|
}
|
|
261
404
|
}
|
|
262
|
-
// Temporary networks/reservations
|
|
263
|
-
const reservationsResult = extractReservations(chatMessage);
|
|
264
405
|
// Handle agent reservations (temporary networks) that come in through the chat stream.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const networkHocon = extractNetworkHocon(chatMessage);
|
|
268
|
-
const agentNetworkDefinition = chatMessage.sly_data?.[AGENT_NETWORK_DEFINITION_KEY];
|
|
269
|
-
// Capture the backend's canonical name so we can bounce it back unchanged on future requests.
|
|
270
|
-
const agentNetworkName = chatMessage.sly_data?.[AGENT_NETWORK_NAME_KEY];
|
|
271
|
-
const newTemporaryNetworks = convertReservationsToNetworks(reservationsResult, networkHocon, agentNetworkDefinition, agentNetworkName);
|
|
406
|
+
const newTemporaryNetworks = extractTemporaryNetworksFromMessage(chatMessage);
|
|
407
|
+
if (newTemporaryNetworks.length > 0) {
|
|
272
408
|
const upserted = useTempNetworksStore.getState().upsertTempNetworks(newTemporaryNetworks);
|
|
273
409
|
// Record the new temporary networks so we can highlight them for the user.
|
|
274
410
|
// For now, we only care about the first one since that's the only active use case
|
|
@@ -276,21 +412,48 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
276
412
|
}
|
|
277
413
|
return true;
|
|
278
414
|
}, [isNetworkDesignerMode]);
|
|
415
|
+
/**
|
|
416
|
+
* Handles a save from the AgentFlow popup: streams the updated definition to the network designer,
|
|
417
|
+
* collects reservations from each chunk, then upserts the result and navigates if the network changed.
|
|
418
|
+
*/
|
|
419
|
+
const onSaveAgent = useCallback(async (agentName, updated, agentNetworkName, signal) => {
|
|
420
|
+
try {
|
|
421
|
+
let newNetworks = [];
|
|
422
|
+
await sendNetworkDesignerUpdate(neuroSanURL, signal, agentName, updated, agentNetworkName, userInfo.userName, (chunk) => {
|
|
423
|
+
newNetworks = collectNetworksFromChunk(chunk, updated, newNetworks);
|
|
424
|
+
});
|
|
425
|
+
if (newNetworks.length === 0) {
|
|
426
|
+
sendNotification(NotificationType.error, `Failed to update network "${agentName}".`, "The network designer did not return a reservation. Please try again.");
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
const replacement = newNetworks.find((n) => n.agentNetworkName === agentNetworkName);
|
|
430
|
+
if (replacement) {
|
|
431
|
+
useTempNetworksStore.getState().upsertTempNetworks(newNetworks);
|
|
432
|
+
if (selectedNetwork) {
|
|
433
|
+
useAgentChatHistoryStore
|
|
434
|
+
.getState()
|
|
435
|
+
.copyHistory(selectedNetwork, replacement.agentInfo.agent_name);
|
|
436
|
+
setSelectedNetwork(replacement.agentInfo.agent_name);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
sendNotification(NotificationType.error, `Failed to update network "${agentName}".`, "A reservation was returned but did not match the current network. Please try again.");
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
catch (e) {
|
|
444
|
+
notifySaveError(agentName, e);
|
|
445
|
+
}
|
|
446
|
+
}, [neuroSanURL, userInfo.userName, selectedNetwork]);
|
|
279
447
|
const onStreamingStarted = useCallback(() => {
|
|
280
448
|
// Reset agent counts
|
|
281
|
-
|
|
449
|
+
setAgentCounts(new Map());
|
|
282
450
|
// Reset newly added temporary networks
|
|
283
451
|
setNewlyAddedTemporaryNetworks(new Set());
|
|
284
452
|
// Reset Agent Network Designer preview
|
|
285
453
|
setAgentsInNetworkDesigner([]);
|
|
286
|
-
// Show info popup only once per session
|
|
287
|
-
if (!haveShownPopup) {
|
|
288
|
-
sendNotification(NotificationType.info, "Agents working", "Click the stop button or hit Escape to exit.");
|
|
289
|
-
setHaveShownPopup(true);
|
|
290
|
-
}
|
|
291
454
|
// Mark that streaming has started
|
|
292
455
|
setIsStreaming(true);
|
|
293
|
-
}, [
|
|
456
|
+
}, []);
|
|
294
457
|
const onStreamingComplete = useCallback(() => {
|
|
295
458
|
// When streaming is complete, clean up any refs and state
|
|
296
459
|
conversationsRef.current = null;
|
|
@@ -298,27 +461,57 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
298
461
|
setAgentsInNetworkDesigner([]);
|
|
299
462
|
resetState();
|
|
300
463
|
}, [resetState]);
|
|
301
|
-
const [confirmationModalOpen, setConfirmationModalOpen] = useState(false);
|
|
302
464
|
const handleDeleteNetwork = (networkId, isExpired) => {
|
|
303
465
|
if (isExpired) {
|
|
304
466
|
// It's expired so just delete it without confirmation
|
|
305
467
|
const tempNetworksWithoutThisOne = temporaryNetworks.filter((network) => network.agentInfo.agent_name !== networkId);
|
|
306
468
|
useTempNetworksStore.getState().setTempNetworks(tempNetworksWithoutThisOne);
|
|
469
|
+
useAgentChatHistoryStore.getState().resetHistory(networkId);
|
|
470
|
+
if (selectedNetwork === networkId) {
|
|
471
|
+
changeSelectedNetwork(null);
|
|
472
|
+
}
|
|
307
473
|
}
|
|
308
474
|
else {
|
|
309
475
|
setNetworkToBeDeleted(networkId);
|
|
310
476
|
setConfirmationModalOpen(true);
|
|
311
477
|
}
|
|
312
478
|
};
|
|
479
|
+
const handleEditNetwork = (_networkId) => {
|
|
480
|
+
setIsEditingNetwork(true);
|
|
481
|
+
};
|
|
482
|
+
useEffect(() => {
|
|
483
|
+
// Don't show the tour modal if any of these are true
|
|
484
|
+
if (haveShownTourModal ||
|
|
485
|
+
tourStatus === TourPromptState.Taken ||
|
|
486
|
+
tourStatus === TourPromptState.DontShowAgain ||
|
|
487
|
+
tourRequested) {
|
|
488
|
+
return undefined;
|
|
489
|
+
}
|
|
490
|
+
// Show tour modal after a delay
|
|
491
|
+
const timer = setTimeout(() => {
|
|
492
|
+
setTourModalOpen(true);
|
|
493
|
+
}, SHOW_TOUR_DELAY_MS);
|
|
494
|
+
return () => {
|
|
495
|
+
clearTimeout(timer);
|
|
496
|
+
};
|
|
497
|
+
}, [haveShownTourModal, tourRequested, tourStatus]);
|
|
498
|
+
useEffect(() => {
|
|
499
|
+
if (!tourRequested)
|
|
500
|
+
return;
|
|
501
|
+
// Determine whether the sample network for the tour is ready
|
|
502
|
+
const networkReady = selectedNetwork != null && agentsInNetwork?.length > 0;
|
|
503
|
+
if (networkReady) {
|
|
504
|
+
setTourStatus(TourPromptState.Taken);
|
|
505
|
+
controls.start();
|
|
506
|
+
setTourRequested(false);
|
|
507
|
+
}
|
|
508
|
+
}, [tourRequested, selectedNetwork, agentsInNetwork, networks, controls, setTourStatus]);
|
|
313
509
|
const getLeftPanel = () => {
|
|
314
510
|
return (_jsx(Slide, { id: "multi-agent-accelerator-grid-sidebar-slide", in: !enableZenMode || !isAwaitingLlm, direction: "right", timeout: GROW_ANIMATION_TIME_MS, onExited: () => {
|
|
315
511
|
setIsStreaming(true);
|
|
316
512
|
}, children: _jsx(Grid, { id: "multi-agent-accelerator-grid-sidebar", size: enableZenMode && isStreaming ? 0 : 3.25, sx: {
|
|
317
513
|
height: "100%",
|
|
318
|
-
}, children: _jsx(Sidebar, { customURLLocalStorage: customURLLocalStorage, customURLCallback: customURLCallback, id: "multi-agent-accelerator-sidebar", isAwaitingLlm: isAwaitingLlm, networks: networks, networkIconSuggestions: networkIconSuggestions, newlyAddedTemporaryNetworks: newlyAddedTemporaryNetworks, onDeleteNetwork: handleDeleteNetwork, setSelectedNetwork: (newNetwork) =>
|
|
319
|
-
agentCountsRef.current = new Map();
|
|
320
|
-
setSelectedNetwork(newNetwork);
|
|
321
|
-
}, temporaryNetworks: temporaryNetworks }) }) }));
|
|
514
|
+
}, children: _jsx(Sidebar, { customURLLocalStorage: customURLLocalStorage, customURLCallback: customURLCallback, id: "multi-agent-accelerator-sidebar", isAwaitingLlm: isAwaitingLlm, networks: networks, networkIconSuggestions: networkIconSuggestions, newlyAddedTemporaryNetworks: newlyAddedTemporaryNetworks, onEditNetwork: handleEditNetwork, onDeleteNetwork: handleDeleteNetwork, setSelectedNetwork: (newNetwork) => changeSelectedNetwork(newNetwork), temporaryNetworks: temporaryNetworks }) }) }));
|
|
322
515
|
};
|
|
323
516
|
const getCenterPanel = () => {
|
|
324
517
|
return (_jsx(Grid, { id: "multi-agent-accelerator-grid-agent-flow", size: enableZenMode && isStreaming ? 18 : 8.25, sx: {
|
|
@@ -331,23 +524,18 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
331
524
|
height: "100%",
|
|
332
525
|
maxWidth: 1000,
|
|
333
526
|
margin: "0 auto",
|
|
334
|
-
}, children: _jsx(AgentFlow, { agentCounts:
|
|
335
|
-
if (selectedNetwork === oldNetworkId) {
|
|
336
|
-
agentCountsRef.current = new Map();
|
|
337
|
-
setSelectedNetwork(newNetworkId);
|
|
338
|
-
}
|
|
339
|
-
}, thoughtBubbleEdges: thoughtBubbleEdges, setThoughtBubbleEdges: setThoughtBubbleEdges }, "multi-agent-accelerator-agent-flow") }) }) }));
|
|
527
|
+
}, children: _jsx(AgentFlow, { agentCounts: agentCounts, agentsInNetwork: agentsInNetwork, agentIconSuggestions: agentIconSuggestions, id: "multi-agent-accelerator-agent-flow", currentConversations: currentConversations, currentUser: userInfo.userName, isAwaitingLlm: isAwaitingLlm, isEditMode: isEditingNetwork, isStreaming: isStreaming, isSelectedNetworkTemporary: isSelectedNetworkTemporary, networkDisplayName: selectedNetwork || undefined, networkId: isSelectedNetworkTemporary ? selectedNetwork : undefined, neuroSanURL: neuroSanURL, onEnterEditMode: () => setIsEditingNetwork(true), onExitEditMode: () => setIsEditingNetwork(false), onNetworkReplaced: (_old, newId) => changeSelectedNetwork(newId), onSaveAgent: onSaveAgent, thoughtBubbleEdges: thoughtBubbleEdges, setThoughtBubbleEdges: setThoughtBubbleEdges }, "multi-agent-accelerator-agent-flow") }) }) }));
|
|
340
528
|
};
|
|
341
529
|
const getRightPanel = () => {
|
|
342
530
|
return (_jsx(Slide, { id: "multi-agent-accelerator-grid-agent-chat-common-slide", in: !enableZenMode || !isAwaitingLlm, direction: "left", timeout: GROW_ANIMATION_TIME_MS, onExited: () => {
|
|
343
531
|
setIsStreaming(true);
|
|
344
532
|
}, children: _jsx(Grid, { id: "multi-agent-accelerator-grid-agent-chat-common", size: enableZenMode && isStreaming ? 0 : 6.5, sx: {
|
|
345
533
|
height: "100%",
|
|
346
|
-
}, children: _jsx(ChatCommon, {
|
|
534
|
+
}, children: _jsx(ChatCommon, { customAgentGreetings: {
|
|
347
535
|
[AGENT_NETWORK_DESIGNER_ID]: "Let's build a network together!",
|
|
348
536
|
}, agentPlaceholders: {
|
|
349
537
|
[AGENT_NETWORK_DESIGNER_ID]: "Describe in plain language the network you would like to build.",
|
|
350
|
-
}, currentUser: userInfo.userName, extraSlyData: extraSlyData, id: "agent-network-ui", isAwaitingLlm: isAwaitingLlm, neuroSanURL: neuroSanURL, onChunkReceived: onChunkReceived, onStreamingComplete: onStreamingComplete, onStreamingStarted: onStreamingStarted, ref: chatRef, setIsAwaitingLlm: setIsAwaitingLlm, targetAgent: selectedNetwork, userImage: userInfo.userImage }, selectedNetwork ?? "no-network") }) }));
|
|
538
|
+
}, currentUser: userInfo.userName, extraSlyData: extraSlyData, id: "agent-network-ui", isAwaitingLlm: isAwaitingLlm, networkDescription: networkDescription, neuroSanURL: neuroSanURL, onChunkReceived: onChunkReceived, onStreamingComplete: onStreamingComplete, onStreamingStarted: onStreamingStarted, ref: chatRef, sampleQueries: sampleQueries, setIsAwaitingLlm: setIsAwaitingLlm, targetAgent: selectedNetwork, userImage: userInfo.userImage }, selectedNetwork ?? "no-network") }) }));
|
|
351
539
|
};
|
|
352
540
|
const getStopButton = () => {
|
|
353
541
|
return (_jsx(_Fragment, { children: isAwaitingLlm && enableZenMode && (_jsx(Box, { id: "stop-button-container", sx: {
|
|
@@ -357,7 +545,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
357
545
|
zIndex: 10,
|
|
358
546
|
}, children: _jsx(SmallLlmChatButton, { "aria-label": "Stop", disabled: !isAwaitingLlm, id: "stop-output-button", onClick: handleExternalStop, posBottom: 8, posRight: 23, children: _jsx(StopCircle, { fontSize: "small", id: "stop-button-icon", sx: { color: "var(--bs-white)" } }) }) })) }));
|
|
359
547
|
};
|
|
360
|
-
const
|
|
548
|
+
const getDeleteNetworkConfirmationModal = () => confirmationModalOpen ? (_jsx(ConfirmationModal, { id: "delete-network-confirmation-modal", content: `The network "${cleanUpAgentName(removeTrailingUuid(networkToBeDeleted))}" will be deleted. ` +
|
|
361
549
|
"This action cannot be undone. Are you sure you want to proceed?", handleCancel: () => {
|
|
362
550
|
setConfirmationModalOpen(false);
|
|
363
551
|
setNetworkToBeDeleted(null);
|
|
@@ -365,9 +553,29 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
365
553
|
useTempNetworksStore
|
|
366
554
|
.getState()
|
|
367
555
|
.setTempNetworks(temporaryNetworks.filter((network) => network.agentInfo.agent_name !== networkToBeDeleted));
|
|
556
|
+
useAgentChatHistoryStore.getState().resetHistory(networkToBeDeleted);
|
|
557
|
+
if (selectedNetwork === networkToBeDeleted) {
|
|
558
|
+
changeSelectedNetwork(null);
|
|
559
|
+
}
|
|
368
560
|
setNetworkToBeDeleted(null);
|
|
369
561
|
setConfirmationModalOpen(false);
|
|
370
562
|
}, title: "Delete Network" })) : null;
|
|
563
|
+
const getTourModal = () => tourModalOpen && (_jsx(MUIDialog, { contentSx: { fontSize: "0.8rem", minWidth: "550px", paddingTop: "0" }, footer: _jsxs(_Fragment, { children: [_jsx(StyledButton, { id: "tour-dont-show-again", onClick: () => {
|
|
564
|
+
setTourStatus(TourPromptState.DontShowAgain);
|
|
565
|
+
dismissTourModal();
|
|
566
|
+
}, variant: "outlined", children: "Don't show this again" }), _jsx(StyledButton, { id: "tour-not-now", onClick: () => {
|
|
567
|
+
dismissTourModal();
|
|
568
|
+
}, variant: "outlined", children: "Not now" }), _jsx(StyledButton, { id: "tour-take", onClick: () => {
|
|
569
|
+
// If no network selected, select one so we have something to show
|
|
570
|
+
if (selectedNetwork == null) {
|
|
571
|
+
setSelectedNetwork(networks?.[0]?.agent_name ?? null);
|
|
572
|
+
}
|
|
573
|
+
dismissTourModal();
|
|
574
|
+
// Defer starting the tour until the selected network's data is available.
|
|
575
|
+
setTourRequested(true);
|
|
576
|
+
}, variant: "contained", children: "Take the tour" })] }), id: "multi-agent-accelerator-tour-modal", isOpen: tourModalOpen, onClose: () => {
|
|
577
|
+
dismissTourModal();
|
|
578
|
+
}, title: "Tour", children: "Would you like to take a tour of the application? (2 mins)" }));
|
|
371
579
|
/**
|
|
372
580
|
* Popper to show real-time progress of the Agent Network Designer output as we receive it from the backend.
|
|
373
581
|
* Only displayed when Agent Network Designer is active.
|
|
@@ -393,7 +601,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
393
601
|
opacity: "95%",
|
|
394
602
|
width: "100%",
|
|
395
603
|
}, children: [_jsx(Typography, { variant: "h6", sx: { padding: "0.5rem 1rem", fontWeight: "bold", color: "white" }, children: "Network Preview" }), agentsInNetworkDesigner?.length > 0 ? (_jsx(AgentFlow, { id: "and-network-preview", agentsInNetwork: agentsInNetworkDesigner, isAgentNetworkDesignerMode: true, isAwaitingLlm: false, isStreaming: false, thoughtBubbleEdges: EMPTY_THOUGHT_BUBBLE_EDGES }, "and-network-preview")) : (_jsx(Typography, { variant: "body1", sx: { color: "white" }, children: "Awaiting status from Agent Network Designer..." }))] }) }) }));
|
|
396
|
-
return (_jsxs(_Fragment, { children: [getProgressPopper(),
|
|
604
|
+
return (_jsxs(_Fragment, { children: [Tour, getTourModal(), getProgressPopper(), getDeleteNetworkConfirmationModal(), _jsxs(Grid, { id: "multi-agent-accelerator-grid", container: true, columns: 18, sx: {
|
|
397
605
|
display: "flex",
|
|
398
606
|
flex: 1,
|
|
399
607
|
height: "85%",
|
|
@@ -4,6 +4,7 @@ import { NodeIndex } from "./TreeBuilder.js";
|
|
|
4
4
|
export interface AgentNetworkNodeProps extends TreeItemProps {
|
|
5
5
|
readonly nodeIndex: NodeIndex;
|
|
6
6
|
readonly onDeleteNetwork?: (network: string, isExpired: boolean) => void;
|
|
7
|
+
readonly onEditNetwork?: (network: string) => void;
|
|
7
8
|
readonly networkIconSuggestions: Record<string, string>;
|
|
8
9
|
readonly temporaryNetworkExpirationTimes?: Record<string, Date>;
|
|
9
10
|
readonly temporaryNetworkHoconStrings?: Record<string, string | null>;
|
|
@@ -5,6 +5,7 @@ import * as MuiIcons from "@mui/icons-material";
|
|
|
5
5
|
import BookmarkIcon from "@mui/icons-material/Bookmark";
|
|
6
6
|
import Delete from "@mui/icons-material/Delete";
|
|
7
7
|
import DownloadIcon from "@mui/icons-material/Download";
|
|
8
|
+
import Edit from "@mui/icons-material/Edit";
|
|
8
9
|
import Box from "@mui/material/Box";
|
|
9
10
|
import Chip from "@mui/material/Chip";
|
|
10
11
|
import IconButton from "@mui/material/IconButton";
|
|
@@ -43,7 +44,7 @@ const isTemporaryNetworkExpired = (expirationDate) => {
|
|
|
43
44
|
* @param props - see AgentNetworkNode interface
|
|
44
45
|
* @returns JSX.Element containing the custom tree item
|
|
45
46
|
*/
|
|
46
|
-
export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, networkIconSuggestions, nodeIndex, onDeleteNetwork, temporaryNetworkExpirationTimes, temporaryNetworkHoconStrings, }) => {
|
|
47
|
+
export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, networkIconSuggestions, nodeIndex, onDeleteNetwork, onEditNetwork, temporaryNetworkExpirationTimes, temporaryNetworkHoconStrings, }) => {
|
|
47
48
|
const theme = useTheme();
|
|
48
49
|
// We know all labels are strings because we set them that way in the tree view items
|
|
49
50
|
const labelString = label;
|
|
@@ -91,13 +92,12 @@ export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, networ
|
|
|
91
92
|
"&:hover": {
|
|
92
93
|
textDecoration: "underline",
|
|
93
94
|
},
|
|
94
|
-
}, children: displayLabel })] }) }), isChild && tags?.length > 0 ? (_jsx(Tooltip, { title: tags
|
|
95
|
-
.slice()
|
|
95
|
+
}, children: displayLabel })] }) }), isChild && tags?.length > 0 ? (_jsx(Tooltip, { title: [...tags]
|
|
96
96
|
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
|
|
97
97
|
.map((tag) => (_jsx(Chip, { label: tag, style: {
|
|
98
98
|
margin: "0.25rem",
|
|
99
99
|
backgroundColor: `var(${tagsToColors.get(tag) || TAG_COLORS[0]})`,
|
|
100
|
-
} }, tag))), placement: "right", arrow: true, children: _jsx(BookmarkIcon, { sx: { fontSize: "0.75rem", color: "var(--bs-accent1-medium)" } }) })) : null, isTemporaryNetwork && networkHocon && (_jsx(Tooltip, { title: isExpired ? "Expired" : "Download network definition", children: _jsx("span", { children: _jsx(IconButton, { onClick: (e) => {
|
|
100
|
+
} }, 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", children: _jsx("span", { children: _jsx(IconButton, { onClick: (e) => {
|
|
101
101
|
e.stopPropagation();
|
|
102
102
|
if (isExpired) {
|
|
103
103
|
return;
|
|
@@ -112,12 +112,28 @@ export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, networ
|
|
|
112
112
|
color: "var(--bs-secondary)",
|
|
113
113
|
opacity: 0.3,
|
|
114
114
|
},
|
|
115
|
-
}, children: _jsx(DownloadIcon, { sx: { fontSize: "0.75rem" } }) }) }) }))
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
115
|
+
}, children: _jsx(DownloadIcon, { sx: { fontSize: "0.75rem" } }) }) }) })), _jsx(Tooltip, { title: "Edit this network", children: _jsx("span", { children: _jsx(IconButton, { onClick: (e) => {
|
|
116
|
+
e.stopPropagation();
|
|
117
|
+
onEditNetwork?.(itemId);
|
|
118
|
+
}, disabled: isExpired, size: "small", sx: {
|
|
119
|
+
padding: 0,
|
|
120
|
+
color: "var(--bs-secondary)",
|
|
121
|
+
"&:hover": { color: "var(--bs-secondary-dark)" },
|
|
122
|
+
"&.Mui-disabled": {
|
|
123
|
+
color: "var(--bs-secondary)",
|
|
124
|
+
opacity: 0.3,
|
|
125
|
+
},
|
|
126
|
+
}, children: _jsx(Edit, { sx: { fontSize: "0.75rem" } }) }) }) }), _jsx(Tooltip, { title: "Delete network", children: _jsx(Delete, { onClick: (e) => {
|
|
127
|
+
e.stopPropagation();
|
|
128
|
+
onDeleteNetwork?.(itemId, isExpired);
|
|
129
|
+
}, sx: {
|
|
130
|
+
color: "var(--bs-secondary)",
|
|
131
|
+
"&:hover": { color: theme.palette.warning.main },
|
|
132
|
+
"&.Mui-disabled": {
|
|
133
|
+
color: "var(--bs-secondary)",
|
|
134
|
+
opacity: 0.3,
|
|
135
|
+
},
|
|
136
|
+
cursor: "pointer",
|
|
137
|
+
fontSize: "1rem",
|
|
138
|
+
} }) })] }))] }) }), children && _jsx(TreeItemGroupTransition, { ...getGroupTransitionProps() })] }) }));
|
|
123
139
|
};
|
|
@@ -10,6 +10,7 @@ export interface SidebarProps {
|
|
|
10
10
|
readonly isAwaitingLlm: boolean;
|
|
11
11
|
readonly networkIconSuggestions?: NetworkIconSuggestions;
|
|
12
12
|
readonly networks: readonly AgentInfo[];
|
|
13
|
+
readonly onEditNetwork?: (network: string) => void;
|
|
13
14
|
readonly onDeleteNetwork?: (network: string, isExpired: boolean) => void;
|
|
14
15
|
readonly setSelectedNetwork: (network: string) => void;
|
|
15
16
|
readonly temporaryNetworks?: readonly TemporaryNetwork[];
|