@cognizant-ai-lab/ui-common 1.7.0 → 1.9.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/README.md +3 -3
- package/dist/Theme/Palettes.d.ts +0 -9
- package/dist/Theme/Palettes.js +0 -18
- package/dist/components/AgentChat/ChatCommon/ChatCommon.d.ts +13 -4
- package/dist/components/AgentChat/ChatCommon/ChatCommon.js +131 -38
- package/dist/components/AgentChat/ChatCommon/ChatHistory.d.ts +7 -0
- package/dist/components/AgentChat/ChatCommon/ChatHistory.js +1 -1
- package/dist/components/AgentChat/ChatCommon/Const.d.ts +1 -0
- package/dist/components/AgentChat/ChatCommon/Const.js +2 -0
- package/dist/components/AgentChat/ChatCommon/ControlButtons.d.ts +5 -3
- package/dist/components/AgentChat/ChatCommon/ControlButtons.js +13 -4
- package/dist/components/AgentChat/ChatCommon/ConversationTurn.d.ts +5 -5
- package/dist/components/AgentChat/ChatCommon/ConversationTurn.js +1 -0
- package/dist/components/AgentChat/ChatCommon/FormattedMarkdown.js +3 -0
- package/dist/components/AgentChat/ChatCommon/SendButton.js +7 -6
- package/dist/components/AgentChat/ChatCommon/SyntaxHighlighterThemes.js +1 -1
- package/dist/components/AgentChat/ChatCommon/Thinking.d.ts +1 -0
- package/dist/components/AgentChat/ChatCommon/Thinking.js +10 -7
- package/dist/components/AgentChat/Common/LlmChatButton.d.ts +0 -2
- package/dist/components/AgentChat/Common/LlmChatButton.js +6 -9
- package/dist/components/AgentChat/Common/Utils.d.ts +4 -0
- package/dist/components/AgentChat/Common/Utils.js +5 -1
- package/dist/components/AgentChat/VoiceChat/MicrophoneButton.js +12 -10
- package/dist/components/Common/Breadcrumbs.js +1 -1
- package/dist/components/Common/Navbar.js +24 -22
- package/dist/components/Common/StatusLight.d.ts +9 -0
- package/dist/components/Common/StatusLight.js +21 -0
- package/dist/components/Common/notification.d.ts +4 -4
- package/dist/components/ErrorPage/ErrorBoundary.js +1 -1
- package/dist/components/ErrorPage/ErrorPage.d.ts +3 -3
- package/dist/components/ErrorPage/ErrorPage.js +4 -3
- package/dist/components/Logo/Common.d.ts +4 -0
- package/dist/components/Logo/Common.js +8 -0
- package/dist/components/Logo/CustomerLogo.d.ts +23 -0
- package/dist/components/Logo/CustomerLogo.js +41 -0
- package/dist/components/MultiAgentAccelerator/AgentConversations.js +0 -1
- package/dist/components/MultiAgentAccelerator/{AgentFlow.d.ts → AgentFlow/AgentFlow.d.ts} +15 -5
- package/dist/components/MultiAgentAccelerator/{AgentFlow.js → AgentFlow/AgentFlow.js} +125 -84
- package/dist/components/MultiAgentAccelerator/{AgentNode.d.ts → AgentFlow/AgentNode.d.ts} +1 -1
- package/dist/components/MultiAgentAccelerator/{AgentNode.js → AgentFlow/AgentNode.js} +26 -30
- package/dist/components/MultiAgentAccelerator/AgentFlow/GraphLayouts.d.ts +43 -0
- package/dist/components/MultiAgentAccelerator/{GraphLayouts.js → AgentFlow/GraphLayouts.js} +10 -41
- package/dist/components/MultiAgentAccelerator/AgentFlow/GraphStructure.d.ts +21 -0
- package/dist/components/MultiAgentAccelerator/AgentFlow/GraphStructure.js +27 -0
- package/dist/components/MultiAgentAccelerator/AgentFlow/PlasmaEdge.d.ts +7 -0
- package/dist/components/MultiAgentAccelerator/{PlasmaEdge.js → AgentFlow/PlasmaEdge.js} +13 -8
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.d.ts +3 -9
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +137 -103
- package/dist/components/MultiAgentAccelerator/Schema/SlyData.d.ts +17 -0
- package/dist/components/MultiAgentAccelerator/Schema/SlyData.js +23 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.d.ts +0 -5
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.js +38 -28
- package/dist/components/MultiAgentAccelerator/Sidebar/ImportNetworkModal.d.ts +67 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/ImportNetworkModal.js +585 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.d.ts +5 -4
- package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.js +77 -168
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.d.ts +31 -13
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.js +177 -100
- package/dist/components/MultiAgentAccelerator/TemporaryNetworks.d.ts +22 -0
- package/dist/components/MultiAgentAccelerator/TemporaryNetworks.js +74 -3
- package/dist/components/MultiAgentAccelerator/{ThoughtBubbleEdge.d.ts → ThoughtBubbles/ThoughtBubbleEdge.d.ts} +1 -1
- package/dist/components/MultiAgentAccelerator/{ThoughtBubbleOverlay.js → ThoughtBubbles/ThoughtBubbleOverlay.js} +1 -1
- package/dist/components/MultiAgentAccelerator/Tour/MainTourSteps.js +15 -8
- package/dist/components/MultiAgentAccelerator/const.d.ts +3 -0
- package/dist/components/MultiAgentAccelerator/const.js +6 -0
- package/dist/components/Settings/ApiKeyInput.js +7 -8
- package/dist/components/Settings/InfoTip.d.ts +8 -0
- package/dist/components/Settings/InfoTip.js +14 -0
- package/dist/components/Settings/SettingsDialog.js +373 -183
- package/dist/components/Settings/SettingsRow.d.ts +18 -0
- package/dist/components/Settings/SettingsRow.js +35 -0
- package/dist/controller/agent/Agent.d.ts +16 -25
- package/dist/controller/agent/Agent.js +24 -54
- package/dist/controller/agent/IconSuggestions.d.ts +35 -0
- package/dist/controller/agent/IconSuggestions.js +85 -0
- package/dist/index.d.ts +1 -3
- package/dist/index.js +1 -3
- package/dist/state/IconSuggestions.d.ts +27 -0
- package/dist/state/IconSuggestions.js +50 -0
- package/dist/state/Settings.d.ts +97 -6
- package/dist/state/Settings.js +110 -8
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/BrowserNavigation.js +2 -0
- package/dist/utils/File.d.ts +4 -1
- package/dist/utils/File.js +4 -9
- package/dist/utils/text.js +3 -7
- package/dist/utils/title.js +1 -1
- package/package.json +9 -6
- package/dist/components/Common/CustomerLogo.d.ts +0 -17
- package/dist/components/Common/CustomerLogo.js +0 -47
- package/dist/components/Common/MUIAccordion.d.ts +0 -17
- package/dist/components/Common/MUIAccordion.js +0 -66
- package/dist/components/MultiAgentAccelerator/GraphLayouts.d.ts +0 -36
- package/dist/components/MultiAgentAccelerator/PlasmaEdge.d.ts +0 -3
- package/dist/utils/useLocalStorage.d.ts +0 -1
- package/dist/utils/useLocalStorage.js +0 -55
- /package/dist/components/MultiAgentAccelerator/{ThoughtBubbleEdge.js → ThoughtBubbles/ThoughtBubbleEdge.js} +0 -0
- /package/dist/components/MultiAgentAccelerator/{ThoughtBubbleOverlay.d.ts → ThoughtBubbles/ThoughtBubbleOverlay.d.ts} +0 -0
|
@@ -35,32 +35,32 @@ import Typography from "@mui/material/Typography";
|
|
|
35
35
|
import { applyNodeChanges, Background, ConnectionMode, ControlButton, Controls, ReactFlow, useReactFlow, useStore, } from "@xyflow/react";
|
|
36
36
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
37
37
|
import { AgentNode, NODE_HEIGHT, NODE_WIDTH } from "./AgentNode.js";
|
|
38
|
-
import {
|
|
39
|
-
import { AGENT_NETWORK_DEFINITION_KEY, AGENT_NETWORK_DESIGNER_ID, AGENT_NETWORK_NAME_KEY, BASE_RADIUS, DEFAULT_FRONTMAN_X_POS, DEFAULT_FRONTMAN_Y_POS, LEVEL_SPACING, } from "./const.js";
|
|
38
|
+
import { AGENT_NETWORK_DEFINITION_KEY, AGENT_NETWORK_DESIGNER_ID, AGENT_NETWORK_NAME_KEY, BASE_RADIUS, DEFAULT_FRONTMAN_X_POS, DEFAULT_FRONTMAN_Y_POS, LEVEL_SPACING, } from "../const.js";
|
|
40
39
|
import { addThoughtBubbleEdge, layoutLinear, layoutRadial } from "./GraphLayouts.js";
|
|
41
40
|
import { PlasmaEdge } from "./PlasmaEdge.js";
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
47
|
-
import {
|
|
48
|
-
import {
|
|
49
|
-
import {
|
|
50
|
-
import {
|
|
51
|
-
import {
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
54
|
-
|
|
55
|
-
|
|
41
|
+
import { sendChatQuery } from "../../../controller/agent/Agent.js";
|
|
42
|
+
import { StreamingUnit } from "../../../controller/llm/LlmChat.js";
|
|
43
|
+
import { useAgentChatHistoryStore } from "../../../state/ChatHistory.js";
|
|
44
|
+
import { usePalette, useSettingsStore } from "../../../state/Settings.js";
|
|
45
|
+
import { useTempNetworksStore } from "../../../state/TemporaryNetworks.js";
|
|
46
|
+
import { getZIndex } from "../../../utils/zIndexLayers.js";
|
|
47
|
+
import { chatMessageFromChunk } from "../../AgentChat/Common/Utils.js";
|
|
48
|
+
import { MUIAlert } from "../../Common/MUIAlert.js";
|
|
49
|
+
import { NotificationType, sendNotification } from "../../Common/notification.js";
|
|
50
|
+
import { AgentNodePopup } from "../AgentNodePopup.js";
|
|
51
|
+
import { convertReservationsToNetworks, extractNetworkHocon, extractReservations, isEditableAgent, mergeNetworks, } from "../TemporaryNetworks.js";
|
|
52
|
+
import { ThoughtBubbleEdge } from "../ThoughtBubbles/ThoughtBubbleEdge.js";
|
|
53
|
+
import { ThoughtBubbleOverlay } from "../ThoughtBubbles/ThoughtBubbleOverlay.js";
|
|
54
|
+
//#endregion: Types
|
|
55
|
+
//#region: Constants
|
|
56
56
|
// Timeout for thought bubbles is set to 10 seconds
|
|
57
57
|
const THOUGHT_BUBBLE_TIMEOUT_MS = 10_000;
|
|
58
|
-
// How long the dock'
|
|
58
|
+
// How long the dock's status banner stays visible before auto-dismissing. Error banners persist until dismissed.
|
|
59
59
|
// Exported for tests.
|
|
60
60
|
export const DOCK_BANNER_AUTO_DISMISS_MS = 5_000;
|
|
61
|
-
// #endregion: Constants
|
|
62
61
|
const DOCK_PROMPT_PLACEHOLDER = "Describe a change to the network";
|
|
63
|
-
|
|
62
|
+
//#endregion: Constants
|
|
63
|
+
//#region: Helpers
|
|
64
64
|
/**
|
|
65
65
|
* Streams the Agent Network Designer endpoint with a natural-language prompt and the current
|
|
66
66
|
* network definition, collecting any returned reservations.
|
|
@@ -86,7 +86,22 @@ const streamNetworkDesignerPrompt = async (neuroSanURL, signal, userPrompt, curr
|
|
|
86
86
|
}, currentUser, StreamingUnit.Line);
|
|
87
87
|
return newNetworks;
|
|
88
88
|
};
|
|
89
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Filters node events based on the current mode. Don't allow any topological-modifying events (adding, deleting nodes)
|
|
91
|
+
* and in Agent Network Designer mode, don't allow dragging nodes (position changes) either.
|
|
92
|
+
* @param change The node change event to filter.
|
|
93
|
+
* @param isAgentNetworkDesignerMode Whether the flow is in Agent Network Designer mode (read-only preview).
|
|
94
|
+
* @return True if the event should be allowed, false if it should be filtered out.
|
|
95
|
+
*/
|
|
96
|
+
export const filterNodeEvents = (change, isAgentNetworkDesignerMode) => {
|
|
97
|
+
// Only allow nodes to be dragged, no topological edits to the graph (read-only)
|
|
98
|
+
if (["remove", "add", "replace"].includes(change.type))
|
|
99
|
+
return false;
|
|
100
|
+
// Disallow dragging nodes in AND mode since it's supposed to be a read-only preview but
|
|
101
|
+
// pass along all other event types as
|
|
102
|
+
return !(change.type === "position" && isAgentNetworkDesignerMode);
|
|
103
|
+
};
|
|
104
|
+
//#endregion: Helpers
|
|
90
105
|
export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork, currentConversations, currentUser, id, isAgentNetworkDesignerMode, isAwaitingLlm, isEditMode, isStreaming, isSelectedNetworkTemporary: isTemporaryNetwork, networkDisplayName, networkId, neuroSanURL, onEnterEditMode, onNetworkReplaced, onExitEditMode, onSaveAgent, thoughtBubbleEdges, setThoughtBubbleEdges, }) => {
|
|
91
106
|
const theme = useTheme();
|
|
92
107
|
const { fitView } = useReactFlow();
|
|
@@ -113,6 +128,8 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
113
128
|
}, []);
|
|
114
129
|
// Ref for isStreaming, read inside the cleanup interval.
|
|
115
130
|
const isStreamingRef = useRef(isStreaming);
|
|
131
|
+
// Display option for agent/network names
|
|
132
|
+
const useNativeNames = useSettingsStore((state) => state.settings.appearance.useNativeNames);
|
|
116
133
|
// Keep the ref current after every render.
|
|
117
134
|
useEffect(() => {
|
|
118
135
|
isStreamingRef.current = isStreaming;
|
|
@@ -166,7 +183,7 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
166
183
|
return edgesMap ?? prev;
|
|
167
184
|
});
|
|
168
185
|
}, [currentConversations, showThoughtBubbles, setThoughtBubbleEdges]);
|
|
169
|
-
//
|
|
186
|
+
// Clean up expired thought bubble edges — created once on mount, reads isStreaming via ref.
|
|
170
187
|
useEffect(() => {
|
|
171
188
|
const cleanupInterval = setInterval(() => {
|
|
172
189
|
if (!isStreamingRef.current)
|
|
@@ -187,9 +204,6 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
187
204
|
}, 1000);
|
|
188
205
|
return () => clearInterval(cleanupInterval);
|
|
189
206
|
}, [setThoughtBubbleEdges]); // mount/unmount only
|
|
190
|
-
// Shadow color for icon
|
|
191
|
-
const isDarkMode = theme.palette.mode === "dark";
|
|
192
|
-
const foregroundColor = isDarkMode ? theme.palette.common.white : theme.palette.common.black;
|
|
193
207
|
const isHeatmap = coloringOption === "heatmap";
|
|
194
208
|
const palette = usePalette();
|
|
195
209
|
// Merge agents from active thought bubbles with agentsInNetwork for layout
|
|
@@ -216,8 +230,28 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
216
230
|
// Create the flow layout depending on user preference
|
|
217
231
|
// Memoize layoutResult so it only recalculates when relevant data changes
|
|
218
232
|
const layoutResult = useMemo(() => layout === "linear"
|
|
219
|
-
? layoutLinear(
|
|
220
|
-
|
|
233
|
+
? layoutLinear({
|
|
234
|
+
agentCounts: isHeatmap ? agentCounts : undefined,
|
|
235
|
+
agentIconSuggestions,
|
|
236
|
+
agentsInNetwork: mergedAgentsInNetwork,
|
|
237
|
+
currentConversations,
|
|
238
|
+
isAgentNetworkDesignerMode,
|
|
239
|
+
isAwaitingLlm,
|
|
240
|
+
isTemporaryNetwork,
|
|
241
|
+
thoughtBubbleEdges,
|
|
242
|
+
useNativeNames,
|
|
243
|
+
})
|
|
244
|
+
: layoutRadial({
|
|
245
|
+
agentCounts: isHeatmap ? agentCounts : undefined,
|
|
246
|
+
agentIconSuggestions,
|
|
247
|
+
agentsInNetwork: mergedAgentsInNetwork,
|
|
248
|
+
currentConversations,
|
|
249
|
+
isAgentNetworkDesignerMode,
|
|
250
|
+
isAwaitingLlm,
|
|
251
|
+
isTemporaryNetwork,
|
|
252
|
+
thoughtBubbleEdges,
|
|
253
|
+
useNativeNames,
|
|
254
|
+
}), [
|
|
221
255
|
agentCounts,
|
|
222
256
|
agentIconSuggestions,
|
|
223
257
|
currentConversations,
|
|
@@ -228,6 +262,7 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
228
262
|
layout,
|
|
229
263
|
mergedAgentsInNetwork,
|
|
230
264
|
thoughtBubbleEdges,
|
|
265
|
+
useNativeNames,
|
|
231
266
|
]);
|
|
232
267
|
const [nodes, setNodes] = useState(layoutResult.nodes);
|
|
233
268
|
// Sync up the nodes with the layout result
|
|
@@ -237,7 +272,7 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
237
272
|
// Track which node the user clicked on so we can open the popup
|
|
238
273
|
const [selectedAgent, setSelectedAgent] = useState(null);
|
|
239
274
|
const [isPopupOpen, setIsPopupOpen] = useState(false);
|
|
240
|
-
// True while the agent-edit request is in-flight so we can disable the Save button.
|
|
275
|
+
// True, while the agent-edit request is in-flight so we can disable the Save button.
|
|
241
276
|
const [isSavingAgent, setIsSavingAgent] = useState(false);
|
|
242
277
|
// AbortController for the in-flight save request — stored in a ref so handlePopupClose can cancel it.
|
|
243
278
|
const saveAbortControllerRef = useRef(null);
|
|
@@ -247,7 +282,7 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
247
282
|
const dockAbortControllerRef = useRef(null);
|
|
248
283
|
// Stop-confirm overlay state: null = not shown, "confirming" = abort dialog open.
|
|
249
284
|
const [stopState, setStopState] = useState(null);
|
|
250
|
-
// Inline status banner shown above the dock header after an apply succeeds, is
|
|
285
|
+
// Inline status banner shown above the dock header after an "apply" succeeds, is canceled, or fails.
|
|
251
286
|
const [dockBanner, setDockBanner] = useState(null);
|
|
252
287
|
const bannerTimeoutRef = useRef(null);
|
|
253
288
|
// Clear the banner auto-dismiss timer on unmount.
|
|
@@ -333,7 +368,7 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
333
368
|
}
|
|
334
369
|
return true;
|
|
335
370
|
}
|
|
336
|
-
// Reservations came back but none matched the current network — surface this in the dock banner.
|
|
371
|
+
// Reservations came back, but none matched the current network — surface this in the dock banner.
|
|
337
372
|
showDockBanner({
|
|
338
373
|
severity: "error",
|
|
339
374
|
title: "Failed to apply network change.",
|
|
@@ -370,15 +405,17 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
370
405
|
}
|
|
371
406
|
catch (e) {
|
|
372
407
|
const isAbort = e instanceof DOMException && e.name === "AbortError";
|
|
373
|
-
if (
|
|
374
|
-
|
|
408
|
+
if (isAbort) {
|
|
409
|
+
if (hasTimedOut) {
|
|
410
|
+
showDockBanner({
|
|
411
|
+
severity: "error",
|
|
412
|
+
title: "Failed to apply network change.",
|
|
413
|
+
detail: "The request timed out. Please try again.",
|
|
414
|
+
});
|
|
415
|
+
}
|
|
375
416
|
}
|
|
376
|
-
else
|
|
377
|
-
showDockBanner({
|
|
378
|
-
severity: "error",
|
|
379
|
-
title: "Failed to apply network change.",
|
|
380
|
-
detail: "The request timed out. Please try again.",
|
|
381
|
-
});
|
|
417
|
+
else {
|
|
418
|
+
showDockBanner({ severity: "error", title: "Failed to apply network change.", detail: String(e) });
|
|
382
419
|
}
|
|
383
420
|
}
|
|
384
421
|
finally {
|
|
@@ -444,10 +481,7 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
444
481
|
}, 50);
|
|
445
482
|
}, [agentsInNetwork, fitView, layout]);
|
|
446
483
|
const onNodesChange = useCallback((changes) => {
|
|
447
|
-
setNodes((currentNodes) => applyNodeChanges(
|
|
448
|
-
// For now, we only allow dragging, no updates. In agent network designer mode, doesn't make sense
|
|
449
|
-
// to allow position changes since the user isn't actually manipulating a real network
|
|
450
|
-
changes.filter((c) => c.type === "position" && !isAgentNetworkDesignerMode), currentNodes));
|
|
484
|
+
setNodes((currentNodes) => applyNodeChanges(changes.filter((change) => filterNodeEvents(change, isAgentNetworkDesignerMode)), currentNodes));
|
|
451
485
|
}, [isAgentNetworkDesignerMode]);
|
|
452
486
|
const transform = useStore((state) => state.transform);
|
|
453
487
|
// Why not just a "const"? See: https://reactflow.dev/learn/customization/custom-nodes
|
|
@@ -479,53 +513,61 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
479
513
|
const getLegend = () => {
|
|
480
514
|
const length = isHeatmap ? palette.length : Math.min(maxDepth, palette.length);
|
|
481
515
|
return (_jsxs(Box, { id: `${id}-legend`, sx: {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
516
|
+
alignItems: "center",
|
|
517
|
+
backgroundColor: theme.palette.background.paper,
|
|
518
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
519
|
+
boxShadow: `0 2px 8px ${alpha(theme.palette.text.primary, 0.18)}`,
|
|
486
520
|
borderRadius: "5px",
|
|
487
|
-
boxShadow: `0 0 5px color-mix(in srgb, ${foregroundColor} 30%, transparent)`,
|
|
488
521
|
display: "flex",
|
|
489
|
-
|
|
522
|
+
padding: theme.spacing(0.5),
|
|
523
|
+
position: "absolute",
|
|
524
|
+
right: theme.spacing(2),
|
|
525
|
+
top: theme.spacing(4),
|
|
490
526
|
zIndex: getZIndex(2, theme),
|
|
491
|
-
}, children: [Array.from({ length }, (_, i) => (_jsx(Box, { id: `${id}-legend-depth-${i}`,
|
|
527
|
+
}, children: [Array.from({ length }, (_, i) => (_jsx(Box, { id: `${id}-legend-depth-${i}`, sx: {
|
|
492
528
|
alignItems: "center",
|
|
493
529
|
backgroundColor: palette[i],
|
|
494
530
|
borderRadius: "50%",
|
|
495
531
|
color: theme.palette.getContrastText(palette[i]),
|
|
496
532
|
display: "flex",
|
|
497
|
-
|
|
533
|
+
fontSize: "0.5rem",
|
|
498
534
|
justifyContent: "center",
|
|
499
|
-
marginLeft:
|
|
535
|
+
marginLeft: theme.spacing(0.75),
|
|
500
536
|
width: "15px",
|
|
501
|
-
}, children:
|
|
502
|
-
fontSize: "8px",
|
|
503
|
-
}, children: i }) }, i))), _jsxs(ToggleButtonGroup, { id: `${id}-coloring-toggle`, value: coloringOption, exclusive: true, onChange: (_, newValue) => {
|
|
537
|
+
}, children: i }, i))), _jsxs(ToggleButtonGroup, { id: `${id}-coloring-toggle`, value: coloringOption, exclusive: true, onChange: (_, newValue) => {
|
|
504
538
|
if (newValue !== null) {
|
|
505
539
|
setColoringOption(newValue);
|
|
506
540
|
}
|
|
507
|
-
}, sx: {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
541
|
+
}, size: "small", sx: {
|
|
542
|
+
marginLeft: theme.spacing(2),
|
|
543
|
+
"& .MuiToggleButton-root": {
|
|
544
|
+
borderColor: theme.palette.divider,
|
|
545
|
+
color: theme.palette.text.primary,
|
|
546
|
+
minHeight: 22,
|
|
547
|
+
px: 1,
|
|
548
|
+
"&:hover": {
|
|
549
|
+
backgroundColor: theme.palette.action.hover,
|
|
550
|
+
},
|
|
551
|
+
"&.Mui-selected": {
|
|
552
|
+
backgroundColor: theme.palette.action.selected,
|
|
553
|
+
borderColor: theme.palette.text.primary,
|
|
554
|
+
},
|
|
555
|
+
"&.Mui-selected:hover": {
|
|
556
|
+
backgroundColor: theme.palette.action.selected,
|
|
557
|
+
borderColor: theme.palette.text.primary,
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
}, children: [_jsx(ToggleButton, { id: `${id}-depth-toggle`, value: "depth", sx: {
|
|
512
561
|
fontSize: "0.5rem",
|
|
513
562
|
height: "1rem",
|
|
514
|
-
}, children: _jsx(
|
|
515
|
-
fontSize: "10px",
|
|
516
|
-
}, children: "Depth" }) }), _jsx(ToggleButton, { id: `${id}-heatmap-toggle`, size: "small", value: "heatmap", sx: {
|
|
563
|
+
}, children: "Depth" }), _jsx(ToggleButton, { id: `${id}-heatmap-toggle`, value: "heatmap", sx: {
|
|
517
564
|
fontSize: "0.5rem",
|
|
518
565
|
height: "1rem",
|
|
519
|
-
}, children:
|
|
520
|
-
fontSize: "10px",
|
|
521
|
-
}, children: "Heatmap" }) })] })] }));
|
|
566
|
+
}, children: "Heatmap" })] })] }));
|
|
522
567
|
};
|
|
523
|
-
// Get the background color for the control buttons based on the
|
|
568
|
+
// Get the background color for the control buttons; differs based on whether the button is active or not
|
|
524
569
|
const getControlButtonBackgroundColor = (isActive) => {
|
|
525
|
-
|
|
526
|
-
return undefined;
|
|
527
|
-
}
|
|
528
|
-
return isDarkMode ? theme.palette.grey[800] : theme.palette.grey[200];
|
|
570
|
+
return isActive ? theme.palette.action.selected : undefined;
|
|
529
571
|
};
|
|
530
572
|
// Only show radial guides if radial layout is selected, radial guides are enabled, and it's not just Frontman
|
|
531
573
|
const shouldShowRadialGuides = enableRadialGuides && layout === "radial" && maxDepth > 1;
|
|
@@ -562,12 +604,10 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
562
604
|
}, children: [_jsx(Tooltip, { title: networkDisplayName, placement: "top", children: _jsx(Box, { sx: { pointerEvents: "auto" }, children: _jsx(Typography, { id: `${id}-network-title`, variant: "subtitle1", sx: {
|
|
563
605
|
backdropFilter: "blur(6px)",
|
|
564
606
|
backgroundColor: titleBackgroundColor,
|
|
565
|
-
border: `1px solid ${alpha(theme.palette.divider, 0.
|
|
607
|
+
border: `1px solid ${alpha(theme.palette.divider, 0.75)}`,
|
|
566
608
|
borderRadius: 2,
|
|
567
|
-
boxShadow: theme.
|
|
568
|
-
|
|
569
|
-
: `0 6px 16px ${alpha(theme.palette.common.black, 0.12)}`,
|
|
570
|
-
color: theme.palette.getContrastText(alpha(titleBackgroundColor, 0.65)),
|
|
609
|
+
boxShadow: theme.shadows[6],
|
|
610
|
+
color: theme.palette.text.primary,
|
|
571
611
|
fontWeight: 600,
|
|
572
612
|
letterSpacing: "0.01em",
|
|
573
613
|
lineHeight: 1.35,
|
|
@@ -592,21 +632,24 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
592
632
|
"& .react-flow__node": {
|
|
593
633
|
border: "1px solid divider",
|
|
594
634
|
},
|
|
595
|
-
"& .react-flow__panel": {
|
|
635
|
+
"& .react-flow__panel, & .react-flow__controls-button": {
|
|
596
636
|
backgroundColor: theme.palette.background.paper,
|
|
597
|
-
border: "1px solid divider",
|
|
598
637
|
color: theme.palette.text.primary,
|
|
599
638
|
},
|
|
639
|
+
"& .react-flow__panel": {
|
|
640
|
+
border: "1px solid divider",
|
|
641
|
+
},
|
|
600
642
|
"& .react-flow__controls-button": {
|
|
601
|
-
backgroundColor: theme.palette.background.paper,
|
|
602
643
|
borderBottom: "1px solid divider",
|
|
603
|
-
color: theme.palette.text.primary,
|
|
604
644
|
fill: theme.palette.text.primary,
|
|
605
645
|
},
|
|
606
|
-
}, children: [_jsxs(Box, { id: `${id}-react-flow-wrapper`, sx: { position: "relative", flex: 1, minHeight: 0 }, children: [networkDisplayName ? _jsx(Box, { sx: { marginBottom: "1rem" }, children: getTitle() }) : null, _jsx(ReactFlow, {
|
|
646
|
+
}, children: [_jsxs(Box, { id: `${id}-react-flow-wrapper`, sx: { position: "relative", flex: 1, minHeight: 0 }, children: [networkDisplayName ? _jsx(Box, { sx: { marginBottom: "1rem" }, children: getTitle() }) : null, _jsx(ReactFlow, { connectionMode: ConnectionMode.Loose, edgeTypes: edgeTypes, edges: edges, fitView: true, id: `${id}-react-flow`, nodeTypes: nodeTypes, nodes: nodes, nodesDraggable: !isAgentNetworkDesignerMode, onNodeClick: handleNodeClick, onNodesChange: onNodesChange, children: !isAwaitingLlm && (_jsxs(_Fragment, { children: [agentsInNetwork?.length && !isAgentNetworkDesignerMode && !isEditMode ? getLegend() : null, _jsx(Background, { id: `${id}-background` }), !isAgentNetworkDesignerMode && !isEditMode && getControls(), shouldShowRadialGuides ? getRadialGuides() : null] })) }), _jsx(ThoughtBubbleOverlay, { nodes: nodes, edges: thoughtBubbleEdgesForOverlay, showThoughtBubbles: showThoughtBubbles, isStreaming: isStreaming, onBubbleHoverChange: handleBubbleHoverChange })] }), isEditMode && isTemporaryNetwork && !isAwaitingLlm && (_jsxs(Box, { sx: {
|
|
647
|
+
backdropFilter: "blur(8px)",
|
|
648
|
+
backgroundColor: alpha(theme.palette.background.paper, 0.2),
|
|
607
649
|
borderTop: `2px solid ${theme.palette.primary.main}`,
|
|
608
|
-
backgroundColor: theme.palette.background.paper,
|
|
609
650
|
flexShrink: 0,
|
|
651
|
+
position: "relative",
|
|
652
|
+
zIndex: getZIndex(2, theme),
|
|
610
653
|
}, children: [dockBanner && (_jsx(MUIAlert, { closeable: true, id: `${id}-dock-banner`, onClose: handleDismissBanner, severity: dockBanner.severity, sx: {
|
|
611
654
|
borderRadius: 0,
|
|
612
655
|
// Override MUIAlert's default 1rem bottom margin so the banner sits flush
|
|
@@ -617,10 +660,8 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
617
660
|
// vertically with the header's close X below it.
|
|
618
661
|
paddingRight: 0.5,
|
|
619
662
|
alignItems: "center",
|
|
620
|
-
// Frost the banner like the dock header so the graph doesn't show through the
|
|
621
|
-
// app's translucent paper background; keep a tinted, mostly
|
|
622
|
-
backdropFilter: "blur(8px)",
|
|
623
|
-
backgroundColor: alpha(theme.palette[dockBanner.severity].main, isDarkMode ? 0.28 : 0.16),
|
|
663
|
+
// Frost the banner like the dock header, so the graph doesn't show through the
|
|
664
|
+
// app's translucent paper background; keep a tinted, mostly opaque severity wash.
|
|
624
665
|
"& .MuiAlert-action": {
|
|
625
666
|
alignItems: "center",
|
|
626
667
|
marginRight: 0,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NodeProps } from "@xyflow/react";
|
|
2
2
|
import type { Node as RFNode } from "@xyflow/react";
|
|
3
3
|
import { FC } from "react";
|
|
4
|
-
import { AgentConversation } from "
|
|
4
|
+
import { AgentConversation } from "../AgentConversations.js";
|
|
5
5
|
export interface AgentNodeProps extends Record<string, unknown> {
|
|
6
6
|
readonly agentCounts?: Map<string, number>;
|
|
7
7
|
readonly agentName: string;
|
|
@@ -28,11 +28,10 @@ import Tooltip from "@mui/material/Tooltip";
|
|
|
28
28
|
import Typography from "@mui/material/Typography";
|
|
29
29
|
import { Handle, Position } from "@xyflow/react";
|
|
30
30
|
import { useState } from "react";
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import { getZIndex } from "../../utils/zIndexLayers.js";
|
|
31
|
+
import { usePalette, useSettingsStore } from "../../../state/Settings.js";
|
|
32
|
+
import { isLightColor } from "../../../Theme/Theme.js";
|
|
33
|
+
import { getZIndex } from "../../../utils/zIndexLayers.js";
|
|
34
|
+
import { DisplayAs } from "../const.js";
|
|
36
35
|
// A zero-width space character, used to give the browser a hint where to break long names
|
|
37
36
|
const ZERO_WIDTH_SPACE = "\u200B";
|
|
38
37
|
// Node dimensions
|
|
@@ -125,32 +124,28 @@ export const AgentNode = (props) => {
|
|
|
125
124
|
// Determine which icon to display based on the agent type whether it is Frontman or not
|
|
126
125
|
const getDisplayAsIcon = () => {
|
|
127
126
|
const id = `${agentId}-icon`;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
// Check for valid MUI icon suggestion from the LLM suggestion service
|
|
128
|
+
const SuggestedIcon = agentIconSuggestion ? MuiIcons[agentIconSuggestion] : undefined;
|
|
129
|
+
// If the LLM provided a valid icon suggestion, use it. Otherwise, fall back to default icons based on
|
|
130
|
+
// agent type.
|
|
131
|
+
if (SuggestedIcon) {
|
|
132
|
+
return (_jsx(SuggestedIcon, { id: id, sx: { fontSize: AGENT_ICON_SIZE } }));
|
|
131
133
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
_jsx(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
case DisplayAs.CODED_TOOL:
|
|
148
|
-
return (_jsx(HandymanIcon, { id: id, sx: { fontSize: AGENT_ICON_SIZE } }));
|
|
149
|
-
case DisplayAs.LLM_AGENT:
|
|
150
|
-
default:
|
|
151
|
-
return (_jsx(AutoAwesomeIcon, { id: id, sx: { fontSize: AGENT_ICON_SIZE } }));
|
|
152
|
-
}
|
|
153
|
-
}
|
|
134
|
+
if (isFrontman) {
|
|
135
|
+
return (
|
|
136
|
+
// Use special icon and larger size for Frontman
|
|
137
|
+
_jsx(PersonIcon, { id: id, sx: { fontSize: FRONTMAN_ICON_SIZE } }));
|
|
138
|
+
}
|
|
139
|
+
switch (displayAs) {
|
|
140
|
+
case DisplayAs.EXTERNAL_AGENT:
|
|
141
|
+
return (_jsx(TravelExploreIcon, { id: id, sx: { fontSize: AGENT_ICON_SIZE } }));
|
|
142
|
+
// This should be a supported type but we're not seeing it?
|
|
143
|
+
case DisplayAs.LANGCHAIN_TOOL:
|
|
144
|
+
case DisplayAs.CODED_TOOL:
|
|
145
|
+
return (_jsx(HandymanIcon, { id: id, sx: { fontSize: AGENT_ICON_SIZE } }));
|
|
146
|
+
case DisplayAs.LLM_AGENT:
|
|
147
|
+
default:
|
|
148
|
+
return (_jsx(AutoAwesomeIcon, { id: id, sx: { fontSize: AGENT_ICON_SIZE } }));
|
|
154
149
|
}
|
|
155
150
|
};
|
|
156
151
|
// Determine icon color based on settings. If auto color is enabled, use contrasting color for readability.
|
|
@@ -160,6 +155,7 @@ export const AgentNode = (props) => {
|
|
|
160
155
|
? theme.palette.common.black
|
|
161
156
|
: theme.palette.common.white;
|
|
162
157
|
const [isHovered, setIsHovered] = useState(false);
|
|
158
|
+
// Insert zero-width spaces into the agent name to give the browser hints where to wrap.
|
|
163
159
|
const wrappedAgentName = agentName
|
|
164
160
|
// Allow wrap after underscore
|
|
165
161
|
.replaceAll("_", `_${ZERO_WIDTH_SPACE}`)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Edge, Node as RFNode } from "@xyflow/react";
|
|
2
|
+
import { AgentConversation } from "../AgentConversations.js";
|
|
3
|
+
import { AgentNodeProps } from "./AgentNode.js";
|
|
4
|
+
import { AgentIconSuggestions } from "../../../controller/Types/AgentIconSuggestions.js";
|
|
5
|
+
import { ConnectivityInfo } from "../../../generated/neuro-san/NeuroSanClient.js";
|
|
6
|
+
import { ThoughtBubbleEdgeShape } from "../ThoughtBubbles/ThoughtBubbleEdge.js";
|
|
7
|
+
export declare const MAX_GLOBAL_THOUGHT_BUBBLES = 5;
|
|
8
|
+
/**
|
|
9
|
+
* Result of the layout algorithms, containing the nodes and edges with their computed positions and properties.
|
|
10
|
+
*/
|
|
11
|
+
export type LayoutResult = {
|
|
12
|
+
nodes: RFNode<AgentNodeProps>[];
|
|
13
|
+
edges: Edge[];
|
|
14
|
+
};
|
|
15
|
+
export declare const addThoughtBubbleEdge: (thoughtBubbleEdges: Map<string, {
|
|
16
|
+
edge: ThoughtBubbleEdgeShape;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
}>, conversationId: string, edge: ThoughtBubbleEdgeShape) => void;
|
|
19
|
+
export declare const removeThoughtBubbleEdge: (thoughtBubbleEdges: Map<string, {
|
|
20
|
+
edge: ThoughtBubbleEdgeShape;
|
|
21
|
+
timestamp: number;
|
|
22
|
+
}>, conversationId: string) => void;
|
|
23
|
+
export declare const getThoughtBubbleEdges: (thoughtBubbleEdges: Map<string, {
|
|
24
|
+
edge: ThoughtBubbleEdgeShape;
|
|
25
|
+
timestamp: number;
|
|
26
|
+
}>) => ThoughtBubbleEdgeShape[];
|
|
27
|
+
/** * Shared options for graph layout functions. */
|
|
28
|
+
export type LayoutOptions = {
|
|
29
|
+
readonly agentCounts: Map<string, number>;
|
|
30
|
+
readonly agentIconSuggestions?: AgentIconSuggestions | null;
|
|
31
|
+
readonly agentsInNetwork: ConnectivityInfo[];
|
|
32
|
+
readonly currentConversations: AgentConversation[] | null;
|
|
33
|
+
readonly isAgentNetworkDesignerMode: boolean;
|
|
34
|
+
readonly isAwaitingLlm: boolean;
|
|
35
|
+
readonly isTemporaryNetwork?: boolean;
|
|
36
|
+
readonly thoughtBubbleEdges: Map<string, {
|
|
37
|
+
edge: ThoughtBubbleEdgeShape;
|
|
38
|
+
timestamp: number;
|
|
39
|
+
}>;
|
|
40
|
+
readonly useNativeNames: boolean;
|
|
41
|
+
};
|
|
42
|
+
export declare const layoutRadial: ({ agentCounts, agentIconSuggestions, agentsInNetwork, currentConversations, isAgentNetworkDesignerMode, isAwaitingLlm, isTemporaryNetwork, thoughtBubbleEdges, useNativeNames, }: LayoutOptions) => LayoutResult;
|
|
43
|
+
export declare const layoutLinear: ({ agentCounts, agentIconSuggestions, agentsInNetwork, currentConversations, isAgentNetworkDesignerMode, isAwaitingLlm, isTemporaryNetwork, thoughtBubbleEdges, useNativeNames, }: LayoutOptions) => LayoutResult;
|
|
@@ -20,9 +20,10 @@ import dagre from "@dagrejs/dagre";
|
|
|
20
20
|
import { MarkerType } from "@xyflow/react";
|
|
21
21
|
import cloneDeep from "lodash-es/cloneDeep.js";
|
|
22
22
|
import { FRONTMAN_SIZE_MULTIPLIER, NODE_HEIGHT, NODE_WIDTH } from "./AgentNode.js";
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
23
|
+
import { cleanUpAgentName, KNOWN_MESSAGE_TYPES_FOR_PLASMA } from "../../AgentChat/Common/Utils.js";
|
|
24
|
+
import { BASE_RADIUS, DEFAULT_FRONTMAN_X_POS, DEFAULT_FRONTMAN_Y_POS, LEVEL_SPACING } from "../const.js";
|
|
25
|
+
import { getFrontman, getParentAgents, getParents } from "./GraphStructure.js";
|
|
26
|
+
import { isEditableAgent } from "../TemporaryNetworks.js";
|
|
26
27
|
export const MAX_GLOBAL_THOUGHT_BUBBLES = 5;
|
|
27
28
|
const FRONTMAN_OFFSET_X = (NODE_WIDTH * (FRONTMAN_SIZE_MULTIPLIER - 1)) / 2;
|
|
28
29
|
const FRONTMAN_OFFSET_Y = (NODE_HEIGHT * (FRONTMAN_SIZE_MULTIPLIER - 1)) / 2;
|
|
@@ -60,34 +61,6 @@ const areInSameConversation = (conversations, sourceAgent, targetAgent) => {
|
|
|
60
61
|
// Name for custom node
|
|
61
62
|
const AGENT_NODE_TYPE_NAME = "agentNode";
|
|
62
63
|
// #endregion: Constants
|
|
63
|
-
/**
|
|
64
|
-
* Returns the "origins" (node names) of the _immediate_ parents of a node in the agent network. Grandparents and
|
|
65
|
-
* higher are not included.
|
|
66
|
-
*
|
|
67
|
-
* @param node Node ID for which to find parents
|
|
68
|
-
* @param parentAgents Full list of parent agents in the network
|
|
69
|
-
* @returns The IDs of the immediate parent nodes for the given node or empty array if no parents are found (frontman)
|
|
70
|
-
*/
|
|
71
|
-
const getParents = (node, parentAgents) => {
|
|
72
|
-
return parentAgents.filter((agent) => agent.tools.includes(node)).map((parentNode) => parentNode.origin);
|
|
73
|
-
};
|
|
74
|
-
// "Parent agents" are those that have tools, aka "child agents"
|
|
75
|
-
const getParentAgents = (agentsInNetwork) => agentsInNetwork.length === 1 ? agentsInNetwork : agentsInNetwork.filter((agent) => agent.tools?.length > 0);
|
|
76
|
-
// "Child agents" are those that are declared as tools by other agents
|
|
77
|
-
const getChildAgents = (parentAgents) => {
|
|
78
|
-
const childAgentsSet = new Set();
|
|
79
|
-
parentAgents.forEach((agent) => {
|
|
80
|
-
agent?.tools?.forEach((tool) => {
|
|
81
|
-
childAgentsSet.add(tool);
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
return childAgentsSet;
|
|
85
|
-
};
|
|
86
|
-
// Frontman is defined as the agent that has no parent. There should be only one in the graph.
|
|
87
|
-
// Frontman is one of the parent agents.
|
|
88
|
-
// There is no explicit field that tells us which agent is the frontman, so we determine it by checking
|
|
89
|
-
// which parent agent does not appear in the set of child agents.
|
|
90
|
-
const getFrontman = (parentAgents, childAgents) => parentAgents.find((agent) => !childAgents.has(agent.origin));
|
|
91
64
|
// Generates the properties for an edge in the graph.
|
|
92
65
|
// Common for both radial and linear layouts.
|
|
93
66
|
const getEdgeProperties = (sourceId, targetId, sourceHandle, targetHandle, isAnimated) => {
|
|
@@ -102,16 +75,14 @@ const getEdgeProperties = (sourceId, targetId, sourceHandle, targetHandle, isAni
|
|
|
102
75
|
type: isAnimated ? "plasmaEdge" : undefined,
|
|
103
76
|
};
|
|
104
77
|
};
|
|
105
|
-
export const layoutRadial = (agentCounts, agentsInNetwork, currentConversations,
|
|
106
|
-
isAwaitingLlm, isAgentNetworkDesignerMode, thoughtBubbleEdges, agentIconSuggestions = null, isTemporaryNetwork = false) => {
|
|
78
|
+
export const layoutRadial = ({ agentCounts, agentIconSuggestions = null, agentsInNetwork, currentConversations, isAgentNetworkDesignerMode, isAwaitingLlm, isTemporaryNetwork = false, thoughtBubbleEdges, useNativeNames, }) => {
|
|
107
79
|
const nodesInNetwork = [];
|
|
108
80
|
const edgesInNetwork = [];
|
|
109
81
|
// Compute depth of each node using breadth-first traversal
|
|
110
82
|
const nodeDepths = new Map();
|
|
111
83
|
const queue = [];
|
|
112
84
|
const parentAgents = getParentAgents(agentsInNetwork);
|
|
113
|
-
const
|
|
114
|
-
const frontman = getFrontman(parentAgents, childAgents);
|
|
85
|
+
const frontman = getFrontman(agentsInNetwork);
|
|
115
86
|
if (frontman) {
|
|
116
87
|
// Add the frontman node to the network
|
|
117
88
|
queue.push({ id: frontman.origin, depth: 0 });
|
|
@@ -186,7 +157,7 @@ isAwaitingLlm, isAgentNetworkDesignerMode, thoughtBubbleEdges, agentIconSuggesti
|
|
|
186
157
|
type: AGENT_NODE_TYPE_NAME,
|
|
187
158
|
data: {
|
|
188
159
|
agentCounts,
|
|
189
|
-
agentName: cleanUpAgentName(nodeId),
|
|
160
|
+
agentName: useNativeNames ? nodeId : cleanUpAgentName(nodeId),
|
|
190
161
|
depth,
|
|
191
162
|
displayAs: agentsInNetwork.find((a) => a.origin === nodeId)?.display_as,
|
|
192
163
|
// Use current conversations for node highlighting (cleared at end)
|
|
@@ -216,14 +187,12 @@ isAwaitingLlm, isAgentNetworkDesignerMode, thoughtBubbleEdges, agentIconSuggesti
|
|
|
216
187
|
edgesInNetwork.push(...thoughtBubbleEdgesToAdd);
|
|
217
188
|
return { nodes: nodesInNetwork, edges: edgesInNetwork };
|
|
218
189
|
};
|
|
219
|
-
export const layoutLinear = (agentCounts, agentsInNetwork, currentConversations,
|
|
220
|
-
isAwaitingLlm, isAgentNetworkDesignerMode, thoughtBubbleEdges, agentIconSuggestions = null, isTemporaryNetwork = false) => {
|
|
190
|
+
export const layoutLinear = ({ agentCounts, agentIconSuggestions = null, agentsInNetwork, currentConversations, isAgentNetworkDesignerMode, isAwaitingLlm, isTemporaryNetwork = false, thoughtBubbleEdges, useNativeNames, }) => {
|
|
221
191
|
const nodesInNetwork = [];
|
|
222
192
|
const edgesInNetwork = [];
|
|
223
193
|
// Do these calculations outside the loop for efficiency
|
|
224
194
|
const parentAgents = getParentAgents(agentsInNetwork);
|
|
225
|
-
const
|
|
226
|
-
const frontman = getFrontman(parentAgents, childAgents);
|
|
195
|
+
const frontman = getFrontman(agentsInNetwork);
|
|
227
196
|
agentsInNetwork.forEach(({ origin: nodeId }) => {
|
|
228
197
|
const parentIds = getParents(nodeId, parentAgents);
|
|
229
198
|
const isFrontman = frontman?.origin === nodeId;
|
|
@@ -232,7 +201,7 @@ isAwaitingLlm, isAgentNetworkDesignerMode, thoughtBubbleEdges, agentIconSuggesti
|
|
|
232
201
|
type: AGENT_NODE_TYPE_NAME,
|
|
233
202
|
data: {
|
|
234
203
|
agentCounts,
|
|
235
|
-
agentName: cleanUpAgentName(nodeId),
|
|
204
|
+
agentName: useNativeNames ? nodeId : cleanUpAgentName(nodeId),
|
|
236
205
|
displayAs: agentsInNetwork.find((a) => a.origin === nodeId)?.display_as,
|
|
237
206
|
// Use current conversations for node highlighting (cleared at end)
|
|
238
207
|
getConversations: () => currentConversations,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ConnectivityInfo } from "../../../generated/neuro-san/NeuroSanClient.js";
|
|
2
|
+
export declare const getParentAgents: <T extends ConnectivityInfo>(agents: readonly T[]) => readonly T[];
|
|
3
|
+
/**
|
|
4
|
+
* Determines the frontman of an agent network — the single source of truth for "who is the frontman".
|
|
5
|
+
*
|
|
6
|
+
* The frontman is the agent with no parent: a "parent" agent (one that has tools) that is not itself
|
|
7
|
+
* listed as a tool by any other agent. A lone single-agent network is its own frontman. Returns
|
|
8
|
+
* undefined when no agent qualifies (e.g. a fully cyclic network); callers decide how to fall back.
|
|
9
|
+
*
|
|
10
|
+
* Consumed by the graph layouts (to seed the depth-0 node) and by the network import flow.
|
|
11
|
+
*/
|
|
12
|
+
export declare const getFrontman: <T extends ConnectivityInfo>(agents: readonly T[]) => T | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Returns the "origins" (node names) of the _immediate_ parents of a node in the agent network. Grandparents and
|
|
15
|
+
* higher are not included.
|
|
16
|
+
*
|
|
17
|
+
* @param node Node ID for which to find parents
|
|
18
|
+
* @param parentAgents Full list of parent agents in the network
|
|
19
|
+
* @returns The IDs of the immediate parent nodes for the given node or empty array if no parents are found (frontman)
|
|
20
|
+
*/
|
|
21
|
+
export declare const getParents: (node: string, parentAgents: readonly ConnectivityInfo[]) => string[];
|