@cognizant-ai-lab/ui-common 1.4.2 → 1.5.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.
Files changed (67) hide show
  1. package/dist/components/AgentChat/ChatCommon/AgentConnectivity.d.ts +14 -0
  2. package/dist/components/AgentChat/ChatCommon/AgentConnectivity.js +23 -0
  3. package/dist/components/AgentChat/{ChatCommon.d.ts → ChatCommon/ChatCommon.d.ts} +8 -4
  4. package/dist/components/AgentChat/{ChatCommon.js → ChatCommon/ChatCommon.js} +318 -307
  5. package/dist/components/AgentChat/ChatCommon/ChatHistory.d.ts +17 -0
  6. package/dist/components/AgentChat/ChatCommon/ChatHistory.js +27 -0
  7. package/dist/components/AgentChat/{ControlButtons.d.ts → ChatCommon/ControlButtons.d.ts} +1 -1
  8. package/dist/components/AgentChat/ChatCommon/ControlButtons.js +26 -0
  9. package/dist/components/AgentChat/{FormattedMarkdown.js → ChatCommon/FormattedMarkdown.js} +1 -1
  10. package/dist/components/AgentChat/ChatCommon/SampleQueries.d.ts +16 -0
  11. package/dist/components/AgentChat/ChatCommon/SampleQueries.js +29 -0
  12. package/dist/components/AgentChat/{SendButton.js → ChatCommon/SendButton.js} +1 -1
  13. package/dist/components/AgentChat/ChatCommon/UserQueryDisplay.d.ts +7 -0
  14. package/dist/components/AgentChat/{UserQueryDisplay.js → ChatCommon/UserQueryDisplay.js} +4 -3
  15. package/dist/components/AgentChat/{LlmChatButton.d.ts → Common/LlmChatButton.d.ts} +2 -2
  16. package/dist/components/AgentChat/{Utils.d.ts → Common/Utils.d.ts} +1 -1
  17. package/dist/components/AgentChat/{Utils.js → Common/Utils.js} +2 -1
  18. package/dist/components/AgentChat/VoiceChat/MicrophoneButton.js +1 -1
  19. package/dist/components/ChatBot/ChatBot.js +2 -2
  20. package/dist/components/Common/CustomerLogo.js +1 -1
  21. package/dist/components/Common/LlmChatOptionsButton.d.ts +1 -1
  22. package/dist/components/Common/MUIDialog.d.ts +1 -0
  23. package/dist/components/Common/MUIDialog.js +2 -2
  24. package/dist/components/MultiAgentAccelerator/AgentCounts.d.ts +2 -2
  25. package/dist/components/MultiAgentAccelerator/AgentFlow.d.ts +13 -1
  26. package/dist/components/MultiAgentAccelerator/AgentFlow.js +193 -20
  27. package/dist/components/MultiAgentAccelerator/AgentNetworkDesigner.d.ts +10 -0
  28. package/dist/components/MultiAgentAccelerator/AgentNetworkDesigner.js +20 -0
  29. package/dist/components/MultiAgentAccelerator/AgentNode.d.ts +1 -0
  30. package/dist/components/MultiAgentAccelerator/AgentNode.js +9 -4
  31. package/dist/components/MultiAgentAccelerator/AgentNodePopup.d.ts +33 -0
  32. package/dist/components/MultiAgentAccelerator/AgentNodePopup.js +81 -0
  33. package/dist/components/MultiAgentAccelerator/GraphLayouts.d.ts +4 -4
  34. package/dist/components/MultiAgentAccelerator/GraphLayouts.js +12 -8
  35. package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.d.ts +1 -0
  36. package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +101 -44
  37. package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.js +4 -4
  38. package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.d.ts +1 -0
  39. package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.js +29 -23
  40. package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.js +1 -1
  41. package/dist/components/MultiAgentAccelerator/TemporaryNetworks.d.ts +14 -0
  42. package/dist/components/MultiAgentAccelerator/TemporaryNetworks.js +26 -1
  43. package/dist/components/MultiAgentAccelerator/ThoughtBubbleOverlay.js +8 -7
  44. package/dist/components/MultiAgentAccelerator/const.d.ts +24 -0
  45. package/dist/components/MultiAgentAccelerator/const.js +19 -0
  46. package/dist/controller/llm/LlmChat.js +1 -1
  47. package/dist/index.d.ts +8 -7
  48. package/dist/index.js +8 -7
  49. package/dist/state/ChatHistory.d.ts +50 -0
  50. package/dist/state/ChatHistory.js +98 -0
  51. package/dist/state/IndexedDBStorage.d.ts +14 -0
  52. package/dist/state/IndexedDBStorage.js +65 -0
  53. package/dist/state/TemporaryNetworks.d.ts +23 -0
  54. package/dist/state/TemporaryNetworks.js +43 -0
  55. package/dist/tsconfig.build.tsbuildinfo +1 -1
  56. package/package.json +8 -2
  57. package/dist/components/AgentChat/ControlButtons.js +0 -26
  58. package/dist/components/AgentChat/UserQueryDisplay.d.ts +0 -5
  59. /package/dist/components/AgentChat/{FormattedMarkdown.d.ts → ChatCommon/FormattedMarkdown.d.ts} +0 -0
  60. /package/dist/components/AgentChat/{Greetings.d.ts → ChatCommon/Greetings.d.ts} +0 -0
  61. /package/dist/components/AgentChat/{Greetings.js → ChatCommon/Greetings.js} +0 -0
  62. /package/dist/components/AgentChat/{SendButton.d.ts → ChatCommon/SendButton.d.ts} +0 -0
  63. /package/dist/components/AgentChat/{SyntaxHighlighterThemes.d.ts → ChatCommon/SyntaxHighlighterThemes.d.ts} +0 -0
  64. /package/dist/components/AgentChat/{SyntaxHighlighterThemes.js → ChatCommon/SyntaxHighlighterThemes.js} +0 -0
  65. /package/dist/components/AgentChat/{LlmChatButton.js → Common/LlmChatButton.js} +0 -0
  66. /package/dist/components/AgentChat/{Types.d.ts → Common/Types.d.ts} +0 -0
  67. /package/dist/components/AgentChat/{Types.js → Common/Types.js} +0 -0
@@ -18,48 +18,35 @@ import StopCircle from "@mui/icons-material/StopCircle";
18
18
  import Box from "@mui/material/Box";
19
19
  import Grid from "@mui/material/Grid";
20
20
  import Slide from "@mui/material/Slide";
21
+ import { useTheme } from "@mui/material/styles";
22
+ import Typography from "@mui/material/Typography";
21
23
  import { ReactFlowProvider } from "@xyflow/react";
22
24
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
23
25
  import { extractConversations } from "./AgentConversations.js";
24
26
  import { getUpdatedAgentCounts } from "./AgentCounts.js";
25
27
  import { AgentFlow } from "./AgentFlow.js";
26
- import { TEMPORARY_NETWORK_FOLDER } from "./const.js";
28
+ 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";
27
30
  import { Sidebar } from "./Sidebar/Sidebar.js";
28
- import { extractNetworkHocon, extractReservations } from "./TemporaryNetworks.js";
31
+ import { convertReservationsToNetworks, extractNetworkHocon, extractReservations } from "./TemporaryNetworks.js";
29
32
  import { getAgentIconSuggestions, getAgentNetworks, getConnectivity, getNetworkIconSuggestions, } from "../../controller/agent/Agent.js";
30
33
  import { useSettingsStore } from "../../state/Settings.js";
31
34
  import { useTempNetworksStore } from "../../state/TemporaryNetworks.js";
32
35
  import { useLocalStorage } from "../../utils/useLocalStorage.js";
33
- import { ChatCommon } from "../AgentChat/ChatCommon.js";
34
- import { SmallLlmChatButton } from "../AgentChat/LlmChatButton.js";
35
- import { chatMessageFromChunk, cleanUpAgentName, removeTrailingUuid } from "../AgentChat/Utils.js";
36
+ import { getZIndex } from "../../utils/zIndexLayers.js";
37
+ import { ChatCommon } from "../AgentChat/ChatCommon/ChatCommon.js";
38
+ import { SmallLlmChatButton } from "../AgentChat/Common/LlmChatButton.js";
39
+ import { chatMessageFromChunk, cleanUpAgentName, removeTrailingUuid } from "../AgentChat/Common/Utils.js";
36
40
  import { ConfirmationModal } from "../Common/ConfirmationModal.js";
37
41
  import { closeNotification, NotificationType, sendNotification } from "../Common/notification.js";
42
+ // Check for expired networks every this many milliseconds
43
+ const EXPIRED_NETWORKS_CHECK_INTERVAL_MS = 10 * 1000;
38
44
  // Display expired temporary networks for this amount of time after they expire so users can see what happened
39
- const GRACE_PERIOD_MS = 5 * 60 * 1000; // 5 minutes
45
+ export const GRACE_PERIOD_MS = 5 * 60 * 1000; // 5 minutes
40
46
  // Animation time for the left and right panels to slide in or out when launching the animation
41
47
  const GROW_ANIMATION_TIME_MS = 800;
42
- /**
43
- * Helper function to convert agent reservations received from the backend into temporary networks that can be displayed
44
- * in the tree.
45
- * @param agentReservations List of "agent reservations" (temporary networks) received from the backend
46
- * @param networkHocon Optional network HOCON string that may be included in the same message as the
47
- * reservations. Note: for now we assume that all reservations are associated with the same network definition.
48
- * This will fail if ever we get multiple reservations for different networks in a single chat stream, but that is
49
- * not a valid scenario currently; we are focusing on Agent Network Design which has a simple output.
50
- * @returns List of TemporaryNetwork objects that can be displayed in the UI
51
- */
52
- const convertReservationsToNetworks = (agentReservations, networkHocon) => {
53
- return agentReservations.map((reservation) => ({
54
- reservation,
55
- agentInfo: {
56
- agent_name: `${TEMPORARY_NETWORK_FOLDER}/${reservation.reservation_id}`,
57
- origin: reservation.reservation_id,
58
- status: "active",
59
- },
60
- networkHocon,
61
- }));
62
- };
48
+ // Optimization to avoid creating a new empty map on every render
49
+ const EMPTY_THOUGHT_BUBBLE_EDGES = new Map();
63
50
  /**
64
51
  * Main Multi-Agent Accelerator component that contains the sidebar, agent flow, and chat components.
65
52
  * @param backendNeuroSanApiUrl Initial URL of the backend Neuro-San API. User can change this in the UI.
@@ -67,6 +54,8 @@ const convertReservationsToNetworks = (agentReservations, networkHocon) => {
67
54
  * @param userInfo Information about the current user, including userName and userImage.
68
55
  */
69
56
  export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
57
+ // MUI theme
58
+ const theme = useTheme();
70
59
  const enableZenMode = useSettingsStore((state) => state.settings.behavior.enableZenMode);
71
60
  // Stores whether are currently awaiting LLM response (for knowing when to show spinners)
72
61
  const [isAwaitingLlm, setIsAwaitingLlm] = useState(false);
@@ -80,8 +69,12 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
80
69
  const [newlyAddedTemporaryNetworks, setNewlyAddedTemporaryNetworks] = useState(new Set());
81
70
  const [networkIconSuggestions, setNetworkIconSuggestions] = useState({});
82
71
  const [agentsInNetwork, setAgentsInNetwork] = useState([]);
72
+ // Agents in network under construction by Agent Network Designer -
73
+ // updated in real time as we receive progress messages from the backend.
74
+ const [agentsInNetworkDesigner, setAgentsInNetworkDesigner] = useState([]);
83
75
  const [agentIconSuggestions, setAgentIconSuggestions] = useState(null);
84
76
  const [selectedNetwork, setSelectedNetwork] = useState(null);
77
+ const networkDisplayName = useMemo(() => cleanUpAgentName(removeTrailingUuid(selectedNetwork)), [selectedNetwork]);
85
78
  // Track whether we've shown the info popup so we don't keep bugging the user with it
86
79
  const [haveShownPopup, setHaveShownPopup] = useState(false);
87
80
  const [customURLLocalStorage, setCustomURLLocalStorage] = useLocalStorage("customAgentNetworkURL", null);
@@ -109,11 +102,30 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
109
102
  }, []);
110
103
  // Reference to the ChatCommon component to allow external stop button to call its handleStop method
111
104
  const chatRef = useRef(null);
105
+ // Special mode of operation where user is using Agent Network Designer to create a new network
106
+ const isNetworkDesignerMode = selectedNetwork === AGENT_NETWORK_DESIGNER_ID;
107
+ // Whether the currently selected network is a temporary network (agent reservation)
108
+ const isSelectedNetworkTemporary = selectedNetwork !== null && temporaryNetworks.some((n) => n.agentInfo.agent_name === selectedNetwork);
109
+ // For temp networks, agent_network_definition and agent_network_name live in localStorage (not IndexedDB slyData).
110
+ // Supply them as extraSlyData so ChatCommon bounces them back to the backend on every request.
111
+ const currentTempNetwork = isSelectedNetworkTemporary
112
+ ? temporaryNetworks.find((n) => n.agentInfo.agent_name === selectedNetwork)
113
+ : undefined;
114
+ const extraSlyData = currentTempNetwork
115
+ ? {
116
+ [AGENT_NETWORK_DEFINITION_KEY]: currentTempNetwork.agentNetworkDefinition,
117
+ // Use the name the backend originally sent, not the local UUID-based key.
118
+ ...(currentTempNetwork.agentNetworkName
119
+ ? { [AGENT_NETWORK_NAME_KEY]: currentTempNetwork.agentNetworkName }
120
+ : {}),
121
+ ...(currentTempNetwork.networkHocon ? { [AGENT_NETWORK_HOCON]: currentTempNetwork.networkHocon } : {}),
122
+ }
123
+ : undefined;
112
124
  // Handle external stop button click - stops streaming and exits zen mode
113
125
  const handleExternalStop = useCallback(() => {
114
126
  chatRef.current?.handleStop();
115
127
  resetState();
116
- }, []);
128
+ }, [resetState]);
117
129
  useEffect(() => {
118
130
  ;
119
131
  (async () => {
@@ -159,8 +171,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
159
171
  closeNotification();
160
172
  }
161
173
  catch (e) {
162
- const networkName = cleanUpAgentName(selectedNetwork);
163
- sendNotification(NotificationType.error, "Connection error", `Unable to get agent list for "${networkName}". Verify that ${neuroSanURL} is a valid ` +
174
+ sendNotification(NotificationType.error, "Connection error", `Unable to get agent list for "${networkDisplayName}". Verify that ${neuroSanURL} is a valid ` +
164
175
  `Multi-Agent Accelerator Server. Error: ${e}.`);
165
176
  setAgentsInNetwork([]);
166
177
  }
@@ -169,7 +180,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
169
180
  setAgentsInNetwork([]);
170
181
  }
171
182
  })();
172
- }, [neuroSanURL, selectedNetwork]);
183
+ }, [networkDisplayName, neuroSanURL, selectedNetwork, userInfo.userName]);
173
184
  useEffect(() => {
174
185
  ;
175
186
  (async () => {
@@ -185,7 +196,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
185
196
  }
186
197
  }
187
198
  })();
188
- }, [agentNamesKey]);
199
+ }, [agentNamesKey, agentsInNetwork]);
189
200
  // Set up handler to allow Escape key to stop the interaction with the LLM.
190
201
  useEffect(() => {
191
202
  if (!isAwaitingLlm) {
@@ -224,7 +235,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
224
235
  setSelectedNetwork(null);
225
236
  agentCountsRef.current = new Map();
226
237
  }
227
- }, 10_000); // check every 10s
238
+ }, EXPIRED_NETWORKS_CHECK_INTERVAL_MS);
228
239
  return () => clearInterval(interval);
229
240
  }, [temporaryNetworks, selectedNetwork]);
230
241
  const onChunkReceived = useCallback((chunk) => {
@@ -241,26 +252,37 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
241
252
  }
242
253
  // Agent hit counts
243
254
  agentCountsRef.current = getUpdatedAgentCounts(agentCountsRef.current, chatMessage?.origin);
255
+ // Agent network designer progress messages
256
+ if (isNetworkDesignerMode) {
257
+ const networkInProgress = extractAgentNetworkDesignerProgress(chatMessage);
258
+ if (networkInProgress?.length > 0) {
259
+ setAgentsInNetworkDesigner(networkInProgress);
260
+ }
261
+ }
244
262
  // Temporary networks/reservations
245
263
  const reservationsResult = extractReservations(chatMessage);
246
264
  // Handle agent reservations (temporary networks) that come in through the chat stream.
247
265
  if (reservationsResult?.length > 0) {
248
266
  // Retrieve network definition, if present
249
267
  const networkHocon = extractNetworkHocon(chatMessage);
250
- const newTemporaryNetworks = convertReservationsToNetworks(reservationsResult, networkHocon);
251
- const currentNetworks = useTempNetworksStore.getState().tempNetworks;
252
- useTempNetworksStore.getState().setTempNetworks([...currentNetworks, ...newTemporaryNetworks]);
253
- // record the new temporary networks so we can select them for the user. For now, we only
254
- // care about the first one.
255
- setNewlyAddedTemporaryNetworks(new Set(newTemporaryNetworks.map((network) => network.agentInfo.agent_name)));
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);
272
+ const upserted = useTempNetworksStore.getState().upsertTempNetworks(newTemporaryNetworks);
273
+ // Record the new temporary networks so we can highlight them for the user.
274
+ // For now, we only care about the first one since that's the only active use case
275
+ setNewlyAddedTemporaryNetworks(new Set(upserted.map((network) => network.agentInfo.agent_name)));
256
276
  }
257
277
  return true;
258
- }, []);
278
+ }, [isNetworkDesignerMode]);
259
279
  const onStreamingStarted = useCallback(() => {
260
280
  // Reset agent counts
261
281
  agentCountsRef.current = new Map();
262
282
  // Reset newly added temporary networks
263
283
  setNewlyAddedTemporaryNetworks(new Set());
284
+ // Reset Agent Network Designer preview
285
+ setAgentsInNetworkDesigner([]);
264
286
  // Show info popup only once per session
265
287
  if (!haveShownPopup) {
266
288
  sendNotification(NotificationType.info, "Agents working", "Click the stop button or hit Escape to exit.");
@@ -273,8 +295,9 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
273
295
  // When streaming is complete, clean up any refs and state
274
296
  conversationsRef.current = null;
275
297
  setCurrentConversations(null);
298
+ setAgentsInNetworkDesigner([]);
276
299
  resetState();
277
- }, [newlyAddedTemporaryNetworks]);
300
+ }, [resetState]);
278
301
  const [confirmationModalOpen, setConfirmationModalOpen] = useState(false);
279
302
  const handleDeleteNetwork = (networkId, isExpired) => {
280
303
  if (isExpired) {
@@ -308,14 +331,23 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
308
331
  height: "100%",
309
332
  maxWidth: 1000,
310
333
  margin: "0 auto",
311
- }, children: _jsx(AgentFlow, { agentCounts: agentCountsRef.current, agentsInNetwork: agentsInNetwork, agentIconSuggestions: agentIconSuggestions, id: "multi-agent-accelerator-agent-flow", currentConversations: currentConversations, isAwaitingLlm: isAwaitingLlm, isStreaming: isStreaming, thoughtBubbleEdges: thoughtBubbleEdges, setThoughtBubbleEdges: setThoughtBubbleEdges }) }) }) }));
334
+ }, children: _jsx(AgentFlow, { agentCounts: agentCountsRef.current, agentsInNetwork: agentsInNetwork, agentIconSuggestions: agentIconSuggestions, currentUser: userInfo.userName, id: "multi-agent-accelerator-agent-flow", currentConversations: currentConversations, isAwaitingLlm: isAwaitingLlm, isStreaming: isStreaming, isSelectedNetworkTemporary: isSelectedNetworkTemporary, networkId: isSelectedNetworkTemporary ? selectedNetwork : undefined, neuroSanURL: neuroSanURL, onNetworkReplaced: (oldNetworkId, newNetworkId) => {
335
+ if (selectedNetwork === oldNetworkId) {
336
+ agentCountsRef.current = new Map();
337
+ setSelectedNetwork(newNetworkId);
338
+ }
339
+ }, thoughtBubbleEdges: thoughtBubbleEdges, setThoughtBubbleEdges: setThoughtBubbleEdges }, "multi-agent-accelerator-agent-flow") }) }) }));
312
340
  };
313
341
  const getRightPanel = () => {
314
342
  return (_jsx(Slide, { id: "multi-agent-accelerator-grid-agent-chat-common-slide", in: !enableZenMode || !isAwaitingLlm, direction: "left", timeout: GROW_ANIMATION_TIME_MS, onExited: () => {
315
343
  setIsStreaming(true);
316
344
  }, children: _jsx(Grid, { id: "multi-agent-accelerator-grid-agent-chat-common", size: enableZenMode && isStreaming ? 0 : 6.5, sx: {
317
345
  height: "100%",
318
- }, children: _jsx(ChatCommon, { ref: chatRef, neuroSanURL: neuroSanURL, id: "agent-network-ui", currentUser: userInfo.userName, userImage: userInfo.userImage, setIsAwaitingLlm: setIsAwaitingLlm, isAwaitingLlm: isAwaitingLlm, targetAgent: selectedNetwork, onChunkReceived: onChunkReceived, onStreamingComplete: onStreamingComplete, onStreamingStarted: onStreamingStarted, clearChatOnNewAgent: true }, selectedNetwork ?? "no-network") }) }));
346
+ }, children: _jsx(ChatCommon, { agentGreetings: {
347
+ [AGENT_NETWORK_DESIGNER_ID]: "Let's build a network together!",
348
+ }, agentPlaceholders: {
349
+ [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") }) }));
319
351
  };
320
352
  const getStopButton = () => {
321
353
  return (_jsx(_Fragment, { children: isAwaitingLlm && enableZenMode && (_jsx(Box, { id: "stop-button-container", sx: {
@@ -336,7 +368,32 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
336
368
  setNetworkToBeDeleted(null);
337
369
  setConfirmationModalOpen(false);
338
370
  }, title: "Delete Network" })) : null;
339
- return (_jsxs(_Fragment, { children: [getConfirmationModal(), _jsxs(Grid, { id: "multi-agent-accelerator-grid", container: true, columns: 18, sx: {
371
+ /**
372
+ * Popper to show real-time progress of the Agent Network Designer output as we receive it from the backend.
373
+ * Only displayed when Agent Network Designer is active.
374
+ */
375
+ const getProgressPopper = () => (_jsx(Box, { sx: {
376
+ display: isStreaming && isNetworkDesignerMode ? "block" : "none",
377
+ position: "absolute",
378
+ top: 0,
379
+ left: 0,
380
+ width: "600px",
381
+ height: "600px",
382
+ zIndex: getZIndex(2, theme),
383
+ }, children: _jsx(ReactFlowProvider, { children: _jsxs(Box, { sx: {
384
+ alignItems: "center",
385
+ background: "var(--bs-secondary)",
386
+ border: "4px solid var(--bs-yellow)",
387
+ display: "flex",
388
+ flexDirection: "column",
389
+ height: "100%",
390
+ justifyContent: "center",
391
+ margin: "0 auto",
392
+ maxWidth: 1000,
393
+ opacity: "95%",
394
+ width: "100%",
395
+ }, 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(), getConfirmationModal(), _jsxs(Grid, { id: "multi-agent-accelerator-grid", container: true, columns: 18, sx: {
340
397
  display: "flex",
341
398
  flex: 1,
342
399
  height: "85%",
@@ -15,7 +15,7 @@ import { TreeItemProvider } from "@mui/x-tree-view/TreeItemProvider";
15
15
  import { useTreeItem } from "@mui/x-tree-view/useTreeItem";
16
16
  import { useRef } from "react";
17
17
  import { downloadFile, toSafeFilename } from "../../../utils/File.js";
18
- import { cleanUpAgentName } from "../../AgentChat/Utils.js";
18
+ import { cleanUpAgentName } from "../../AgentChat/Common/Utils.js";
19
19
  // Palette of colors we can use for tags
20
20
  const TAG_COLORS = [
21
21
  "--bs-accent2-light",
@@ -79,7 +79,7 @@ export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, networ
79
79
  else if (iconNameSuggestion) {
80
80
  console.warn(`Icon "${iconNameSuggestion}" not found in MUI icons library.`);
81
81
  }
82
- return (_jsx(TreeItemProvider, { ...getContextProviderProps(), children: _jsxs(TreeItemRoot, { ...getRootProps(), ref: rootRef, children: [_jsx(TreeItemContent, { ...getContentProps(), sx: {
82
+ return (_jsx(TreeItemProvider, { ...getContextProviderProps(), children: _jsxs(TreeItemRoot, { ...getRootProps(), ref: rootRef, "data-itemid": itemId, children: [_jsx(TreeItemContent, { ...getContentProps(), sx: {
83
83
  cursor: isExpired ? "not-allowed" : "pointer",
84
84
  }, children: _jsxs(Box, { sx: { display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%" }, children: [_jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: "0.25rem" }, children: [_jsx(Tooltip, { title: isChild && isExpired
85
85
  ? "Expired"
@@ -97,7 +97,7 @@ export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, networ
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 ? "Network 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, isTemporaryNetwork && 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;
@@ -119,5 +119,5 @@ export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, networ
119
119
  cursor: "pointer",
120
120
  fontSize: "1rem",
121
121
  "&:hover": { color: theme.palette.warning.main },
122
- } }) }))] }) }, labelString), children && _jsx(TreeItemGroupTransition, { ...getGroupTransitionProps() })] }) }));
122
+ } }) }))] }) }), children && _jsx(TreeItemGroupTransition, { ...getGroupTransitionProps() })] }) }));
123
123
  };
@@ -2,6 +2,7 @@ import { FC } from "react";
2
2
  import { NetworkIconSuggestions } from "../../../controller/Types/NetworkIconSuggestions.js";
3
3
  import { AgentInfo } from "../../../generated/neuro-san/NeuroSanClient.js";
4
4
  import { TemporaryNetwork } from "../../../state/TemporaryNetworks.js";
5
+ export declare const SPARKLE_HIGHLIGHT_CLASS = "sparkle-highlight";
5
6
  export interface SidebarProps {
6
7
  readonly customURLCallback: (url: string) => void;
7
8
  readonly customURLLocalStorage?: string;
@@ -14,6 +14,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
14
  See the License for the specific language governing permissions and
15
15
  limitations under the License.
16
16
  */
17
+ import AddBoxRounded from "@mui/icons-material/AddBoxRounded";
17
18
  import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline";
18
19
  import ClearIcon from "@mui/icons-material/Clear";
19
20
  import HighlightOff from "@mui/icons-material/HighlightOff";
@@ -34,7 +35,7 @@ import { buildTreeViewItems } from "./TreeBuilder.js";
34
35
  import { testConnection } from "../../../controller/agent/Agent.js";
35
36
  import { useEnvironmentStore } from "../../../state/Environment.js";
36
37
  import { getZIndex } from "../../../utils/zIndexLayers.js";
37
- import { TEMPORARY_NETWORK_FOLDER } from "../const.js";
38
+ import { AGENT_NETWORK_DESIGNER_ID, TEMPORARY_NETWORK_FOLDER } from "../const.js";
38
39
  // Animation for the sparkle effect when a new temporary network is added.
39
40
  const sparkle = keyframes `
40
41
  0% {
@@ -75,6 +76,8 @@ const PrimaryButton = styled(Button)({
75
76
  marginLeft: "0.5rem",
76
77
  marginTop: "2px",
77
78
  });
79
+ // Name for sparkle animation CSS class
80
+ export const SPARKLE_HIGHLIGHT_CLASS = "sparkle-highlight";
78
81
  // Styled component for Sidebar aside element, including styles for the sparkle highlight animation
79
82
  // when a new temporary network is added.
80
83
  const SidebarAside = styled("aside")({
@@ -83,7 +86,7 @@ const SidebarAside = styled("aside")({
83
86
  height: "100%",
84
87
  overflowY: "auto",
85
88
  paddingRight: "0.75rem",
86
- "& .sparkle-highlight": {
89
+ [`& .${SPARKLE_HIGHLIGHT_CLASS}`]: {
87
90
  background: "linear-gradient(90deg, gold, orange, cyan, magenta, gold)",
88
91
  backgroundSize: "400% 100%",
89
92
  animation: `${sparkle} 5s ease`,
@@ -94,11 +97,14 @@ const SidebarAside = styled("aside")({
94
97
  });
95
98
  // Styled component for the sidebar heading, which is sticky at the top of the sidebar.
96
99
  const SidebarHeading = styled("h2")(({ theme }) => ({
100
+ alignItems: "center",
97
101
  backgroundColor: theme.palette.background.default,
98
102
  borderBottomStyle: "solid",
99
103
  borderBottomWidth: "1px",
104
+ display: "flex",
100
105
  fontSize: "1.125rem",
101
106
  fontWeight: "bold",
107
+ justifyContent: "space-between",
102
108
  marginBottom: "0.25rem",
103
109
  paddingBottom: "0.75rem",
104
110
  position: "sticky",
@@ -129,8 +135,7 @@ export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaiti
129
135
  const settingsPopoverOpen = Boolean(settingsAnchorEl);
130
136
  const [expandedItems, setExpandedItems] = useState([]);
131
137
  // Theming/Dark mode
132
- const theme = useTheme();
133
- const darkMode = theme.palette.mode === "dark";
138
+ const darkMode = useTheme().palette.mode === "dark";
134
139
  const handleSettingsClick = (event) => {
135
140
  // On open of Settings popover, reset the connection status to idle
136
141
  setConnectionStatus(CONNECTION_STATUS.IDLE);
@@ -186,18 +191,17 @@ export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaiti
186
191
  setUrlInput("");
187
192
  setConnectionStatus(CONNECTION_STATUS.IDLE);
188
193
  };
189
- // Get Neuro-san version on initial load
194
+ // Fetch Neuro-san version on load and whenever the saved URL changes
190
195
  useEffect(() => {
191
196
  const fetchVersion = async () => {
192
197
  // We aren't really trying to test the connection here, just getting the version.
193
- const result = await testConnection(urlInput);
198
+ const result = await testConnection(customURLLocalStorage || backendNeuroSanApiUrl);
194
199
  if (result.success) {
195
200
  setTestConnectionResult(result);
196
- setConnectionStatus(CONNECTION_STATUS.SUCCESS);
197
201
  }
198
202
  };
199
203
  void fetchVersion();
200
- }, []);
204
+ }, [customURLLocalStorage, backendNeuroSanApiUrl]);
201
205
  const { treeViewItems, nodeIndex } = buildTreeViewItems(networks, temporaryNetworks);
202
206
  const temporaryNetworkExpirationTimes = temporaryNetworks.reduce((acc, tempNetwork) => {
203
207
  acc[tempNetwork.agentInfo.agent_name] = new Date(tempNetwork.reservation.expiration_time_in_seconds * 1000);
@@ -228,23 +232,22 @@ export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaiti
228
232
  useEffect(() => {
229
233
  let highlightTimeout;
230
234
  let removeHighlightTimeout;
231
- // If we got a new temporary network, select it and expand the temporary category in the tree view
235
+ // If we got a new temporary network, expand the temporary category in the tree view
232
236
  if (newlyAddedTemporaryNetworks?.size > 0) {
233
237
  const firstItem = newlyAddedTemporaryNetworks.values().next().value;
234
- setSelectedItem(firstItem);
235
- setSelectedNetwork(firstItem);
236
238
  setExpandedItems((prev) => prev.includes(TEMPORARY_NETWORK_FOLDER) ? prev : [...prev, TEMPORARY_NETWORK_FOLDER]);
237
239
  highlightTimeout = setTimeout(() => {
238
- // Scroll the selected node into view and add an animation to draw the user's attention to it.
239
- // Hacky: use a DOM query to find the node. I tried the various ways to do this programmatically
240
- // in MUI RichTreeView including the imperative API (https://mui.com/x/react-tree-view/rich-tree-view/selection/#imperative-api)
241
- // but couldn't get it to work so resorting to this for now.
242
- const selectedNode = document.querySelector("[role=treeitem][aria-checked=true]");
243
- if (selectedNode) {
244
- selectedNode.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
245
- selectedNode.classList.add("sparkle-highlight");
240
+ /* Scroll the selected node into view and add an animation to draw the user's attention to it.
241
+ Hacky: use a DOM query to find the node. I tried the various ways to do this programmatically
242
+ in MUI RichTreeView including the imperative API (https://mui.com/x/react-tree-view/rich-tree-view/selection/#imperative-api)
243
+ but couldn't get it to work so resorting to this for now.
244
+ */
245
+ const temporaryNetworkNode = document.querySelector(`[data-itemid="${firstItem}"]`);
246
+ if (temporaryNetworkNode) {
247
+ temporaryNetworkNode.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
248
+ temporaryNetworkNode.classList.add(SPARKLE_HIGHLIGHT_CLASS);
246
249
  removeHighlightTimeout = setTimeout(() => {
247
- selectedNode.classList.remove("sparkle-highlight");
250
+ temporaryNetworkNode.classList.remove(SPARKLE_HIGHLIGHT_CLASS);
248
251
  }, 5000);
249
252
  }
250
253
  }, 50);
@@ -254,9 +257,12 @@ export const Sidebar = ({ customURLCallback, customURLLocalStorage, id, isAwaiti
254
257
  clearTimeout(removeHighlightTimeout);
255
258
  };
256
259
  }, [newlyAddedTemporaryNetworks]);
257
- return (_jsxs(_Fragment, { children: [_jsxs(SidebarAside, { id: `${id}-sidebar`, children: [_jsxs(SidebarHeading, { id: `${id}-heading`, children: ["Agent Networks", _jsx(Button, { "aria-label": "Agent Network Settings", disabled: isAwaitingLlm, id: "agent-network-settings-btn", onClick: handleSettingsClick, sx: { display: "inline-block", minWidth: "40px" }, children: _jsx(Tooltip, { id: "agent-network-settings-tooltip", placement: "top", title: `${customURLLocalStorage || backendNeuroSanApiUrl}\nversion: ${testConnectionResult?.version || "unknown"}`, children: _jsx(SettingsIcon, { id: "agent-network-settings-icon", sx: {
258
- color: isAwaitingLlm ? "rgba(0, 0, 0, 0.12)" : "var(--bs-secondary)",
259
- } }) }) })] }), _jsx(RichTreeView, { items: treeViewItems, expandedItems: expandedItems, onExpandedItemsChange: (_event, itemIds) => setExpandedItems(itemIds), multiSelect: false, onSelectedItemsChange: handleSelectedItemsChange, selectedItems: selectedItem, disableSelection: isAwaitingLlm, slots: {
260
+ return (_jsxs(_Fragment, { children: [_jsxs(SidebarAside, { id: `${id}-sidebar`, children: [_jsxs(SidebarHeading, { id: `${id}-heading`, children: ["Agent Networks", _jsxs(Box, { sx: { display: "flex" }, children: [_jsx(Button, { "aria-label": "Add New Network", disabled: isAwaitingLlm, id: "add-network-btn", onClick: () => {
261
+ setSelectedItem(AGENT_NETWORK_DESIGNER_ID);
262
+ setSelectedNetwork(AGENT_NETWORK_DESIGNER_ID);
263
+ }, 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: { color: isAwaitingLlm ? "rgba(0, 0, 0, 0.12)" : "var(--bs-secondary)" } }) }) }), _jsx(Button, { "aria-label": "Agent Network Settings", disabled: isAwaitingLlm, id: "agent-network-settings-btn", onClick: handleSettingsClick, sx: { display: "inline-block", minWidth: "40px" }, children: _jsx(Tooltip, { id: "agent-network-settings-tooltip", placement: "top", title: `${customURLLocalStorage || backendNeuroSanApiUrl}\nversion: ${testConnectionResult?.version || "unknown"}`, children: _jsx(SettingsIcon, { id: "agent-network-settings-icon", sx: {
264
+ color: isAwaitingLlm ? "rgba(0, 0, 0, 0.12)" : "var(--bs-secondary)",
265
+ } }) }) })] })] }), _jsx(RichTreeView, { items: treeViewItems, expandedItems: expandedItems, onExpandedItemsChange: (_event, itemIds) => setExpandedItems(itemIds), multiSelect: false, onSelectedItemsChange: handleSelectedItemsChange, selectedItems: selectedItem, disableSelection: isAwaitingLlm, slots: {
260
266
  item: AgentNetworkTreeItem,
261
267
  },
262
268
  // Pass custom props to tree items via slotProps.
@@ -1,4 +1,4 @@
1
- import { cleanUpAgentName, removeTrailingUuid } from "../../AgentChat/Utils.js";
1
+ import { cleanUpAgentName, removeTrailingUuid } from "../../AgentChat/Common/Utils.js";
2
2
  /**
3
3
  * Iteratively sort all children of tree nodes using a queue-based approach
4
4
  * @param nodes - Array of tree nodes to sort
@@ -1,4 +1,6 @@
1
+ import { AgentNetworkDefinitionEntry } from "./const.js";
1
2
  import { ChatMessage } from "../../generated/neuro-san/NeuroSanClient.js";
3
+ import { TemporaryNetwork } from "../../state/TemporaryNetworks.js";
2
4
  /**
3
5
  * Definition of a temporary network. No schema for this provided by backend so we second-guess it here.
4
6
  * @see https://github.com/cognizant-ai-lab/neuro-san/issues/743
@@ -31,3 +33,15 @@ export declare const extractReservations: (message: ChatMessage) => AgentReserva
31
33
  * @return The network HOCON as a string, or null if not found or not the right type of message.
32
34
  */
33
35
  export declare const extractNetworkHocon: (message: ChatMessage) => string | null;
36
+ /**
37
+ * Converts a list of agent reservations received from the backend into TemporaryNetwork objects that can be
38
+ * displayed in the UI.
39
+ * @param agentReservations List of "agent reservations" (temporary networks) received from the backend
40
+ * @param networkHocon Optional network HOCON string associated with the reservations.
41
+ * @param agentNetworkDefinition Optional agent network definition entries.
42
+ * @param agentNetworkName Optional backend canonical network name used to match / deduplicate networks.
43
+ * When omitted, the name is derived from the reservation_id via {@link extractNetworkNameFromReservationId}.
44
+ * @returns List of TemporaryNetwork objects ready for the store.
45
+ */
46
+ export declare const convertReservationsToNetworks: (agentReservations: AgentReservation[], networkHocon: string | null, agentNetworkDefinition?: AgentNetworkDefinitionEntry[], agentNetworkName?: string) => TemporaryNetwork[];
47
+ export { extractNetworkNameFromReservationId } from "../../state/TemporaryNetworks.js";
@@ -1,5 +1,6 @@
1
- import { AGENT_NETWORK_HOCON, AGENT_RESERVATIONS_KEY } from "./const.js";
1
+ import { AGENT_NETWORK_HOCON, AGENT_RESERVATIONS_KEY, TEMPORARY_NETWORK_FOLDER, } from "./const.js";
2
2
  import { ChatMessageType } from "../../generated/neuro-san/NeuroSanClient.js";
3
+ import { extractNetworkNameFromReservationId } from "../../state/TemporaryNetworks.js";
3
4
  /**
4
5
  * Extracts agent reservations from a chat message, if they exist.
5
6
  * @param message The chat message to extract reservations from. We expect reservations to be present in messages of
@@ -33,3 +34,27 @@ export const extractNetworkHocon = (message) => {
33
34
  return null;
34
35
  }
35
36
  };
37
+ /**
38
+ * Converts a list of agent reservations received from the backend into TemporaryNetwork objects that can be
39
+ * displayed in the UI.
40
+ * @param agentReservations List of "agent reservations" (temporary networks) received from the backend
41
+ * @param networkHocon Optional network HOCON string associated with the reservations.
42
+ * @param agentNetworkDefinition Optional agent network definition entries.
43
+ * @param agentNetworkName Optional backend canonical network name used to match / deduplicate networks.
44
+ * When omitted, the name is derived from the reservation_id via {@link extractNetworkNameFromReservationId}.
45
+ * @returns List of TemporaryNetwork objects ready for the store.
46
+ */
47
+ export const convertReservationsToNetworks = (agentReservations, networkHocon, agentNetworkDefinition, agentNetworkName) => {
48
+ return agentReservations.map((reservation) => ({
49
+ reservation,
50
+ agentInfo: {
51
+ agent_name: `${TEMPORARY_NETWORK_FOLDER}/${reservation.reservation_id}`,
52
+ },
53
+ // Use the explicit name when provided; fall back to extracting it from the reservation_id so that
54
+ // networks are always deduplicated by name even when the backend omits AGENT_NETWORK_NAME_KEY.
55
+ agentNetworkName: agentNetworkName ?? extractNetworkNameFromReservationId(reservation.reservation_id),
56
+ networkHocon,
57
+ agentNetworkDefinition,
58
+ }));
59
+ };
60
+ export { extractNetworkNameFromReservationId } from "../../state/TemporaryNetworks.js";
@@ -115,12 +115,12 @@ export const ThoughtBubbleOverlay = ({ nodes, edges, showThoughtBubbles = true,
115
115
  // Handle bubble lifecycle (appear/disappear animations)
116
116
  useEffect(() => {
117
117
  const currentEdgeIds = new Set(thoughtBubbleEdges.map((e) => e.id));
118
- const previousBubbleIds = new Set(bubbleStates.keys());
119
- // Find new bubbles that should appear
120
- const newBubbles = thoughtBubbleEdges.filter((e) => !previousBubbleIds.has(e.id));
121
- // Find bubbles that should disappear
122
- const removingBubbles = Array.from(previousBubbleIds).filter((id) => !currentEdgeIds.has(id));
123
118
  setBubbleStates((prev) => {
119
+ const previousBubbleIds = new Set(prev.keys());
120
+ // Find new bubbles that should appear
121
+ const newBubbles = thoughtBubbleEdges.filter((e) => !previousBubbleIds.has(e.id));
122
+ // Find bubbles that should disappear
123
+ const removingBubbles = Array.from(previousBubbleIds).filter((id) => !currentEdgeIds.has(id));
124
124
  const newState = new Map(prev);
125
125
  // Add new bubbles in entering state. Record when they entered so we can delay showing
126
126
  // connecting lines until the bubble's entrance animation delay.
@@ -155,9 +155,10 @@ export const ThoughtBubbleOverlay = ({ nodes, edges, showThoughtBubbles = true,
155
155
  }, [thoughtBubbleEdges]);
156
156
  // Cleanup timeouts on unmount
157
157
  useEffect(() => {
158
+ const timeouts = animationTimeouts.current;
158
159
  return () => {
159
- animationTimeouts.current.forEach((timeout) => clearTimeout(timeout));
160
- animationTimeouts.current.clear();
160
+ timeouts.forEach((timeout) => clearTimeout(timeout));
161
+ timeouts.clear();
161
162
  };
162
163
  }, []);
163
164
  // Sort edges to prioritize frontman's edges first
@@ -1,3 +1,4 @@
1
+ import { ConnectivityInfo } from "../../generated/neuro-san/NeuroSanClient.js";
1
2
  export declare const DEFAULT_FRONTMAN_X_POS = 150;
2
3
  export declare const DEFAULT_FRONTMAN_Y_POS = 450;
3
4
  export declare const BASE_RADIUS = 100;
@@ -5,3 +6,26 @@ export declare const LEVEL_SPACING = 150;
5
6
  export declare const TEMPORARY_NETWORK_FOLDER = "temporary";
6
7
  export declare const AGENT_RESERVATIONS_KEY = "agent_reservations";
7
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
+ export declare const AGENT_NETWORK_DEFINITION_KEY = "agent_network_definition";
12
+ export declare const AGENT_NETWORK_NAME_KEY = "agent_network_name";
13
+ /**
14
+ * A single agent entry within an agent network definition, as received in sly_data from the backend.
15
+ * Extends ConnectivityInfo with editable instructions and description fields for the Agent Network Designer.
16
+ */
17
+ export type AgentNetworkDefinitionEntry = ConnectivityInfo & {
18
+ readonly instructions?: string;
19
+ readonly description?: string;
20
+ };
21
+ /** Possible values for the `display_as` field in ConnectivityInfo / AgentNetworkDefinitionEntry. */
22
+ export declare const DISPLAY_AS_LLM_AGENT = "llm_agent";
23
+ export declare const DISPLAY_AS_CODED_TOOL = "coded_tool";
24
+ export declare const DISPLAY_AS_LANGCHAIN_TOOL = "langchain_tool";
25
+ export declare const DISPLAY_AS_EXTERNAL_AGENT = "external_agent";
26
+ /**
27
+ * Returns true when an agent node supports the edit popup (instructions + description).
28
+ * Only `llm_agent` nodes (and the Frontman, whose `display_as` is undefined) are editable.
29
+ * `coded_tool`, `langchain_tool`, `external_agent`, and any other types are read-only.
30
+ */
31
+ export declare const isEditableAgent: (displayAs: string | undefined) => boolean;
@@ -27,3 +27,22 @@ export const TEMPORARY_NETWORK_FOLDER = "temporary";
27
27
  export const AGENT_RESERVATIONS_KEY = "agent_reservations";
28
28
  // We expect the agent network HOCON to be stored in sly_data under this key, if it is provided by the backend
29
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
+ // The key in sly_data where the agent network definition is stored
35
+ export const AGENT_NETWORK_DEFINITION_KEY = "agent_network_definition";
36
+ // The key in sly_data where the agent network name is stored
37
+ export const AGENT_NETWORK_NAME_KEY = "agent_network_name";
38
+ /** Possible values for the `display_as` field in ConnectivityInfo / AgentNetworkDefinitionEntry. */
39
+ export const DISPLAY_AS_LLM_AGENT = "llm_agent";
40
+ export const DISPLAY_AS_CODED_TOOL = "coded_tool";
41
+ export const DISPLAY_AS_LANGCHAIN_TOOL = "langchain_tool";
42
+ export const DISPLAY_AS_EXTERNAL_AGENT = "external_agent";
43
+ /**
44
+ * Returns true when an agent node supports the edit popup (instructions + description).
45
+ * Only `llm_agent` nodes (and the Frontman, whose `display_as` is undefined) are editable.
46
+ * `coded_tool`, `langchain_tool`, `external_agent`, and any other types are read-only.
47
+ */
48
+ export const isEditableAgent = (displayAs) => displayAs === DISPLAY_AS_LLM_AGENT;
@@ -24,7 +24,7 @@ export var StreamingUnit;
24
24
  })(StreamingUnit || (StreamingUnit = {}));
25
25
  const handleStreamingCallback = async (res, callback, streamingUnit) => {
26
26
  const reader = res.body.getReader();
27
- const utf8decoder = new TextDecoder("utf8");
27
+ const utf8decoder = new TextDecoder("utf-8");
28
28
  let buffer = "";
29
29
  while (true) {
30
30
  const { done, value } = await reader.read();