@cognizant-ai-lab/ui-common 1.5.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AgentChat/ChatCommon/ChatCommon.d.ts +16 -6
- package/dist/components/AgentChat/ChatCommon/ChatCommon.js +250 -166
- package/dist/components/AgentChat/ChatCommon/ChatHistory.d.ts +1 -7
- package/dist/components/AgentChat/ChatCommon/ChatHistory.js +33 -22
- package/dist/components/AgentChat/ChatCommon/Conversation.d.ts +3 -5
- package/dist/components/AgentChat/ChatCommon/Conversation.js +35 -57
- package/dist/components/AgentChat/ChatCommon/ConversationTurn.d.ts +9 -5
- package/dist/components/AgentChat/ChatCommon/ConversationTurn.js +3 -2
- 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 +13 -7
- package/dist/components/ChatBot/ChatBot.d.ts +0 -4
- package/dist/components/ChatBot/ChatBot.js +2 -2
- 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 -1
- package/dist/components/Common/CustomerLogo.js +1 -3
- package/dist/components/Common/MUIAlert.d.ts +1 -0
- package/dist/components/Common/MUIAlert.js +3 -4
- package/dist/components/MultiAgentAccelerator/AgentFlow.d.ts +1 -0
- package/dist/components/MultiAgentAccelerator/AgentFlow.js +154 -59
- package/dist/components/MultiAgentAccelerator/AgentNode.d.ts +1 -0
- package/dist/components/MultiAgentAccelerator/AgentNode.js +46 -45
- package/dist/components/MultiAgentAccelerator/GraphLayouts.js +12 -4
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +103 -24
- package/dist/components/Settings/ApiKeyInput.d.ts +16 -0
- package/dist/components/Settings/ApiKeyInput.js +70 -0
- package/dist/components/Settings/SettingsDialog.js +30 -3
- package/dist/controller/llm/Providers.d.ts +2 -0
- package/dist/controller/llm/Providers.js +41 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/state/Settings.d.ts +2 -0
- package/dist/state/Settings.js +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/dist/components/AgentChat/ChatCommon/AgentConnectivity.d.ts +0 -14
- package/dist/components/AgentChat/ChatCommon/AgentConnectivity.js +0 -23
- package/dist/components/AgentChat/ChatCommon/AgentIntro.d.ts +0 -12
- package/dist/components/AgentChat/ChatCommon/AgentIntro.js +0 -19
- package/dist/components/AgentChat/ChatCommon/AgentMetadata.d.ts +0 -14
- package/dist/components/AgentChat/ChatCommon/AgentMetadata.js +0 -43
- package/dist/components/AgentChat/ChatCommon/Const.d.ts +0 -1
- package/dist/components/AgentChat/ChatCommon/Const.js +0 -2
- 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
|
@@ -30,14 +30,13 @@ const StyledAlert = styled(Alert)({
|
|
|
30
30
|
},
|
|
31
31
|
});
|
|
32
32
|
// #endregion: Types
|
|
33
|
-
export const MUIAlert = ({ children, closeable = false, id, severity, sx }) => {
|
|
33
|
+
export const MUIAlert = ({ children, closeable = false, id, onClose, severity, sx }) => {
|
|
34
34
|
const [alertOpen, setAlertOpen] = useState(true);
|
|
35
35
|
const handleClose = () => {
|
|
36
36
|
setAlertOpen(false);
|
|
37
|
+
onClose?.();
|
|
37
38
|
};
|
|
38
|
-
return (_jsx(Collapse, { id: `${id}-collapse`, in: alertOpen, children: _jsx(StyledAlert, { action: closeable && (_jsx(IconButton, { "aria-label": "close", color: "inherit", id: `${id}-icon-button`, onClick:
|
|
39
|
-
setAlertOpen(false);
|
|
40
|
-
}, size: "small", sx: {
|
|
39
|
+
return (_jsx(Collapse, { id: `${id}-collapse`, in: alertOpen, children: _jsx(StyledAlert, { action: closeable && (_jsx(IconButton, { "aria-label": "close", color: "inherit", id: `${id}-icon-button`, onClick: handleClose, size: "small", sx: {
|
|
41
40
|
bottom: "2px",
|
|
42
41
|
position: "relative",
|
|
43
42
|
}, children: _jsx(CloseIcon, { fontSize: "inherit", id: `${id}-close-icon` }) })), id: id, onClose: closeable ? handleClose : undefined, severity: severity, sx: sx, children: children }) }));
|
|
@@ -20,6 +20,7 @@ import CloseIcon from "@mui/icons-material/Close";
|
|
|
20
20
|
import EditIcon from "@mui/icons-material/Edit";
|
|
21
21
|
import HubOutlinedIcon from "@mui/icons-material/HubOutlined";
|
|
22
22
|
import ScatterPlotOutlinedIcon from "@mui/icons-material/ScatterPlotOutlined";
|
|
23
|
+
import Backdrop from "@mui/material/Backdrop";
|
|
23
24
|
import Box from "@mui/material/Box";
|
|
24
25
|
import Button from "@mui/material/Button";
|
|
25
26
|
import CircularProgress from "@mui/material/CircularProgress";
|
|
@@ -48,11 +49,15 @@ import { useTempNetworksStore } from "../../state/TemporaryNetworks.js";
|
|
|
48
49
|
import { usePalette } from "../../Theme/Palettes.js";
|
|
49
50
|
import { getZIndex } from "../../utils/zIndexLayers.js";
|
|
50
51
|
import { chatMessageFromChunk } from "../AgentChat/Common/Utils.js";
|
|
52
|
+
import { MUIAlert } from "../Common/MUIAlert.js";
|
|
51
53
|
import { NotificationType, sendNotification } from "../Common/notification.js";
|
|
52
54
|
// #endregion: Types
|
|
53
55
|
// #region: Constants
|
|
54
56
|
// Timeout for thought bubbles is set to 10 seconds
|
|
55
57
|
const THOUGHT_BUBBLE_TIMEOUT_MS = 10_000;
|
|
58
|
+
// How long the dock'sstatus banner stays visible before auto-dismissing. Error banners persist until dismissed.
|
|
59
|
+
// Exported for tests.
|
|
60
|
+
export const DOCK_BANNER_AUTO_DISMISS_MS = 5_000;
|
|
56
61
|
// #endregion: Constants
|
|
57
62
|
const DOCK_PROMPT_PLACEHOLDER = "Describe a change to the network";
|
|
58
63
|
// #region: Helpers
|
|
@@ -240,6 +245,45 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
240
245
|
const [dockPrompt, setDockPrompt] = useState("");
|
|
241
246
|
const [isDockStreaming, setIsDockStreaming] = useState(false);
|
|
242
247
|
const dockAbortControllerRef = useRef(null);
|
|
248
|
+
// Stop-confirm overlay state: null = not shown, "confirming" = abort dialog open.
|
|
249
|
+
const [stopState, setStopState] = useState(null);
|
|
250
|
+
// Inline status banner shown above the dock header after an apply succeeds, is cancelled, or fails.
|
|
251
|
+
const [dockBanner, setDockBanner] = useState(null);
|
|
252
|
+
const bannerTimeoutRef = useRef(null);
|
|
253
|
+
// Clear the banner auto-dismiss timer on unmount.
|
|
254
|
+
useEffect(() => {
|
|
255
|
+
return () => {
|
|
256
|
+
clearTimeout(bannerTimeoutRef.current);
|
|
257
|
+
};
|
|
258
|
+
}, []);
|
|
259
|
+
const handleDismissBanner = useCallback(() => {
|
|
260
|
+
clearTimeout(bannerTimeoutRef.current);
|
|
261
|
+
setDockBanner(null);
|
|
262
|
+
}, []);
|
|
263
|
+
// Show a dock banner. Success/cancel banners auto-dismiss; error banners persist until dismissed.
|
|
264
|
+
const showDockBanner = useCallback((banner) => {
|
|
265
|
+
clearTimeout(bannerTimeoutRef.current);
|
|
266
|
+
setDockBanner(banner);
|
|
267
|
+
if (banner.severity !== "error") {
|
|
268
|
+
bannerTimeoutRef.current = setTimeout(() => setDockBanner(null), DOCK_BANNER_AUTO_DISMISS_MS);
|
|
269
|
+
}
|
|
270
|
+
}, []);
|
|
271
|
+
const handleStopClick = useCallback(() => {
|
|
272
|
+
setStopState("confirming");
|
|
273
|
+
}, []);
|
|
274
|
+
const handleKeepApplying = useCallback(() => {
|
|
275
|
+
setStopState(null);
|
|
276
|
+
}, []);
|
|
277
|
+
const handleStopAndDiscard = useCallback(() => {
|
|
278
|
+
dockAbortControllerRef.current?.abort();
|
|
279
|
+
dockAbortControllerRef.current = null;
|
|
280
|
+
setStopState(null);
|
|
281
|
+
showDockBanner({
|
|
282
|
+
severity: "info",
|
|
283
|
+
title: "Applying cancelled.",
|
|
284
|
+
detail: "Nothing was changed. Your prompt is restored below.",
|
|
285
|
+
});
|
|
286
|
+
}, [showDockBanner]);
|
|
243
287
|
const handleNodeClick = useCallback((_event, node) => {
|
|
244
288
|
// Popup is only available for temporary networks.
|
|
245
289
|
if (!isTemporaryNetwork)
|
|
@@ -267,11 +311,18 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
267
311
|
setIsPopupOpen(false);
|
|
268
312
|
setIsSavingAgent(false);
|
|
269
313
|
}, []);
|
|
270
|
-
/**
|
|
271
|
-
|
|
314
|
+
/**
|
|
315
|
+
* Applies the networks returned by the designer: upserts them and triggers navigation if needed.
|
|
316
|
+
* Returns true when a matching reservation was applied, false (and surfaces an error banner) otherwise.
|
|
317
|
+
*/
|
|
318
|
+
const applyNetworkSaveResult = useCallback((newNetworksFromSave, currentAgentNetworkName) => {
|
|
272
319
|
if (newNetworksFromSave.length === 0) {
|
|
273
|
-
|
|
274
|
-
|
|
320
|
+
showDockBanner({
|
|
321
|
+
severity: "error",
|
|
322
|
+
title: "Failed to apply network change.",
|
|
323
|
+
detail: "The network designer did not return a reservation. Please try again.",
|
|
324
|
+
});
|
|
325
|
+
return false;
|
|
275
326
|
}
|
|
276
327
|
const replacement = newNetworksFromSave.find((n) => n.agentNetworkName === currentAgentNetworkName);
|
|
277
328
|
if (replacement) {
|
|
@@ -280,12 +331,16 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
280
331
|
useAgentChatHistoryStore.getState().copyHistory(networkId, replacement.agentInfo.agent_name);
|
|
281
332
|
onNetworkReplaced(networkId, replacement.agentInfo.agent_name);
|
|
282
333
|
}
|
|
334
|
+
return true;
|
|
283
335
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
336
|
+
// Reservations came back but none matched the current network — surface this in the dock banner.
|
|
337
|
+
showDockBanner({
|
|
338
|
+
severity: "error",
|
|
339
|
+
title: "Failed to apply network change.",
|
|
340
|
+
detail: "A reservation was returned but did not match the current network. Please try again.",
|
|
341
|
+
});
|
|
342
|
+
return false;
|
|
343
|
+
}, [networkId, onNetworkReplaced, showDockBanner]);
|
|
289
344
|
const handleDockApply = useCallback(async () => {
|
|
290
345
|
if (!dockPrompt.trim() || !neuroSanURL || !currentUser)
|
|
291
346
|
return;
|
|
@@ -303,17 +358,27 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
303
358
|
}, 120_000); // 2 min timeout
|
|
304
359
|
try {
|
|
305
360
|
const newNetworks = await streamNetworkDesignerPrompt(neuroSanURL, controller.signal, dockPrompt, currentDefinition, currentTempNetwork?.agentNetworkName, currentUser);
|
|
306
|
-
applyNetworkSaveResult(
|
|
307
|
-
|
|
361
|
+
const applied = applyNetworkSaveResult(newNetworks, currentTempNetwork?.agentNetworkName);
|
|
362
|
+
if (applied) {
|
|
363
|
+
setDockPrompt("");
|
|
364
|
+
showDockBanner({
|
|
365
|
+
severity: "success",
|
|
366
|
+
title: "Changes applied.",
|
|
367
|
+
detail: "Your network has been updated.",
|
|
368
|
+
});
|
|
369
|
+
}
|
|
308
370
|
}
|
|
309
371
|
catch (e) {
|
|
310
372
|
const isAbort = e instanceof DOMException && e.name === "AbortError";
|
|
311
373
|
if (!isAbort) {
|
|
312
|
-
|
|
374
|
+
showDockBanner({ severity: "error", title: "Failed to apply network change.", detail: String(e) });
|
|
313
375
|
}
|
|
314
376
|
else if (hasTimedOut) {
|
|
315
|
-
|
|
316
|
-
|
|
377
|
+
showDockBanner({
|
|
378
|
+
severity: "error",
|
|
379
|
+
title: "Failed to apply network change.",
|
|
380
|
+
detail: "The request timed out. Please try again.",
|
|
381
|
+
});
|
|
317
382
|
}
|
|
318
383
|
}
|
|
319
384
|
finally {
|
|
@@ -321,7 +386,7 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
321
386
|
dockAbortControllerRef.current = null;
|
|
322
387
|
setIsDockStreaming(false);
|
|
323
388
|
}
|
|
324
|
-
}, [applyNetworkSaveResult, currentUser, dockPrompt, networkId, neuroSanURL, tempNetworks]);
|
|
389
|
+
}, [applyNetworkSaveResult, currentUser, dockPrompt, networkId, neuroSanURL, showDockBanner, tempNetworks]);
|
|
325
390
|
const handleExitEditMode = useCallback(() => {
|
|
326
391
|
if (isDockStreaming) {
|
|
327
392
|
dockAbortControllerRef.current?.abort();
|
|
@@ -508,10 +573,8 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
508
573
|
lineHeight: 1.35,
|
|
509
574
|
maxWidth: 400,
|
|
510
575
|
overflow: "hidden",
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
paddingBottom: 0.45,
|
|
514
|
-
paddingTop: 0.45,
|
|
576
|
+
px: 2,
|
|
577
|
+
py: 0.45,
|
|
515
578
|
textOverflow: "ellipsis",
|
|
516
579
|
whiteSpace: "nowrap",
|
|
517
580
|
}, children: networkDisplayName }) }) }), isTemporaryNetwork && !isEditMode && !isAwaitingLlm && onEnterEditMode && (_jsx(Button, { id: `${id}-enter-edit-mode-btn`, variant: "contained", size: "small", onClick: onEnterEditMode, startIcon: _jsx(EditIcon, {}), sx: {
|
|
@@ -527,67 +590,99 @@ export const AgentFlow = ({ agentCounts, agentIconSuggestions, agentsInNetwork,
|
|
|
527
590
|
width: "100%",
|
|
528
591
|
backgroundColor: theme.palette.background.default,
|
|
529
592
|
"& .react-flow__node": {
|
|
530
|
-
border:
|
|
593
|
+
border: "1px solid divider",
|
|
531
594
|
},
|
|
532
595
|
"& .react-flow__panel": {
|
|
533
596
|
backgroundColor: theme.palette.background.paper,
|
|
534
|
-
border:
|
|
597
|
+
border: "1px solid divider",
|
|
535
598
|
color: theme.palette.text.primary,
|
|
536
599
|
},
|
|
537
600
|
"& .react-flow__controls-button": {
|
|
538
601
|
backgroundColor: theme.palette.background.paper,
|
|
539
|
-
borderBottom:
|
|
602
|
+
borderBottom: "1px solid divider",
|
|
540
603
|
color: theme.palette.text.primary,
|
|
541
604
|
fill: theme.palette.text.primary,
|
|
542
605
|
},
|
|
543
|
-
}, 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, { id: `${id}-react-flow`, nodes: nodes, edges: edges, onNodesChange: onNodesChange, onNodeClick: handleNodeClick, fitView: true, nodeTypes: nodeTypes, edgeTypes: edgeTypes, connectionMode: ConnectionMode.Loose, children: !isAwaitingLlm && (_jsxs(_Fragment, { children: [agentsInNetwork?.length && !isAgentNetworkDesignerMode && !isEditMode ? getLegend() : null, _jsx(Background, { id: `${id}-background` }), !isAgentNetworkDesignerMode && !isEditMode && getControls(), shouldShowRadialGuides ? getRadialGuides() : null] })) }),
|
|
544
|
-
position: "absolute",
|
|
545
|
-
inset: 0,
|
|
546
|
-
zIndex: getZIndex(2, theme),
|
|
547
|
-
backgroundColor: alpha(theme.palette.background.default, 0.65),
|
|
548
|
-
display: "flex",
|
|
549
|
-
alignItems: "center",
|
|
550
|
-
justifyContent: "center",
|
|
551
|
-
}, children: _jsxs(Paper, { elevation: 6, sx: {
|
|
552
|
-
display: "flex",
|
|
553
|
-
alignItems: "center",
|
|
554
|
-
gap: 2,
|
|
555
|
-
px: 4,
|
|
556
|
-
py: 2.5,
|
|
557
|
-
borderRadius: 2,
|
|
558
|
-
maxWidth: 480,
|
|
559
|
-
}, children: [_jsx(CircularProgress, { id: `${id}-dock-applying-spinner`, size: 24 }), _jsxs(Box, { children: [_jsx(Typography, { id: `${id}-dock-applying-title`, variant: "body1", sx: {
|
|
560
|
-
fontWeight: "bold",
|
|
561
|
-
}, children: "Applying changes to network" }), dockPrompt && (_jsx(Typography, { id: `${id}-dock-applying-prompt`, variant: "body2", sx: {
|
|
562
|
-
color: "text.secondary",
|
|
563
|
-
mt: 0.25,
|
|
564
|
-
}, children: dockPrompt }))] })] }) })), _jsx(ThoughtBubbleOverlay, { nodes: nodes, edges: thoughtBubbleEdgesForOverlay, showThoughtBubbles: showThoughtBubbles, isStreaming: isStreaming, onBubbleHoverChange: handleBubbleHoverChange })] }), isEditMode && isTemporaryNetwork && !isAwaitingLlm && (_jsxs(Box, { id: `${id}-topology-editor-dock`, sx: {
|
|
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, { id: `${id}-react-flow`, nodes: nodes, edges: edges, onNodesChange: onNodesChange, onNodeClick: handleNodeClick, fitView: true, nodeTypes: nodeTypes, edgeTypes: edgeTypes, connectionMode: ConnectionMode.Loose, 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: {
|
|
565
607
|
borderTop: `2px solid ${theme.palette.primary.main}`,
|
|
566
608
|
backgroundColor: theme.palette.background.paper,
|
|
567
609
|
flexShrink: 0,
|
|
568
|
-
}, children: [
|
|
610
|
+
}, children: [dockBanner && (_jsx(MUIAlert, { closeable: true, id: `${id}-dock-banner`, onClose: handleDismissBanner, severity: dockBanner.severity, sx: {
|
|
611
|
+
borderRadius: 0,
|
|
612
|
+
// Override MUIAlert's default 1rem bottom margin so the banner sits flush
|
|
613
|
+
// against the dock header below it.
|
|
614
|
+
marginBottom: 0,
|
|
615
|
+
py: 0,
|
|
616
|
+
// Match the dock header's right padding so the banner's close X lines up
|
|
617
|
+
// vertically with the header's close X below it.
|
|
618
|
+
paddingRight: 0.5,
|
|
619
|
+
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-opaque severity wash.
|
|
622
|
+
backdropFilter: "blur(8px)",
|
|
623
|
+
backgroundColor: alpha(theme.palette[dockBanner.severity].main, isDarkMode ? 0.28 : 0.16),
|
|
624
|
+
"& .MuiAlert-action": {
|
|
625
|
+
alignItems: "center",
|
|
626
|
+
marginRight: 0,
|
|
627
|
+
paddingTop: 0,
|
|
628
|
+
},
|
|
629
|
+
}, children: _jsxs(Typography, { variant: "caption", component: "span", children: [_jsx("strong", { children: dockBanner.title }), ` ${dockBanner.detail}`] }) })), _jsxs(Box, { sx: {
|
|
630
|
+
backdropFilter: "blur(6px)",
|
|
631
|
+
borderBottom: "1px solid divider",
|
|
569
632
|
display: "flex",
|
|
570
633
|
alignItems: "center",
|
|
571
634
|
justifyContent: "space-between",
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}, children: [_jsx(Typography, { variant: "overline", sx: { fontWeight: "bold", letterSpacing: 1, lineHeight: 1.8 }, children: "Network Editor" }), _jsx(IconButton, { size: "small", "aria-label": "close edit mode", onClick: handleExitEditMode, children: _jsx(CloseIcon, { fontSize: "small" }) })] }), _jsx(Typography, { variant: "caption", sx: {
|
|
576
|
-
px: 2,
|
|
577
|
-
pt: 0.5,
|
|
578
|
-
pb: 0,
|
|
579
|
-
color: theme.palette.text.secondary,
|
|
580
|
-
display: "block",
|
|
581
|
-
}, children: "Changes apply only to this Temporary network" }), _jsxs(Box, { sx: {
|
|
635
|
+
paddingLeft: 1.25,
|
|
636
|
+
paddingRight: 0.25,
|
|
637
|
+
}, children: [_jsx(Typography, { variant: "overline", sx: { fontWeight: "bold", letterSpacing: 1, lineHeight: 1.8 }, children: "Network Editor" }), _jsx(IconButton, { size: "small", "aria-label": "close edit mode", onClick: handleExitEditMode, children: _jsx(CloseIcon, { fontSize: "small" }) })] }), _jsxs(Box, { sx: {
|
|
582
638
|
display: "flex",
|
|
583
639
|
gap: 1,
|
|
584
|
-
px:
|
|
585
|
-
py:
|
|
640
|
+
px: 1,
|
|
641
|
+
py: 0.5,
|
|
586
642
|
alignItems: "center",
|
|
587
|
-
}, children: [_jsx(TextField, { fullWidth: true,
|
|
643
|
+
}, children: [_jsx(TextField, { fullWidth: true, placeholder: DOCK_PROMPT_PLACEHOLDER, variant: "outlined", size: "small", value: dockPrompt, onChange: (e) => setDockPrompt(e.target.value), onKeyDown: (e) => {
|
|
588
644
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
589
645
|
e.preventDefault();
|
|
590
646
|
void handleDockApply();
|
|
591
647
|
}
|
|
592
|
-
}, disabled: isDockStreaming, slotProps: { htmlInput: { style: { fontSize: "0.
|
|
648
|
+
}, disabled: isDockStreaming, slotProps: { htmlInput: { style: { fontSize: "0.75rem" } } } }), _jsx(Button, { variant: "contained", onClick: () => void handleDockApply(), disabled: isDockStreaming || !dockPrompt.trim(), sx: {
|
|
649
|
+
fontSize: 16,
|
|
650
|
+
marginBottom: "1px",
|
|
651
|
+
marginRight: 0,
|
|
652
|
+
minWidth: 110,
|
|
653
|
+
paddingTop: 0.3,
|
|
654
|
+
paddingBottom: 0.3,
|
|
655
|
+
whiteSpace: "nowrap",
|
|
656
|
+
}, startIcon: isDockStreaming ? (_jsx(CircularProgress, { size: 16, color: "inherit" })) : undefined, children: isDockStreaming ? "Applying..." : "Apply" })] })] })), selectedAgent && !isAwaitingLlm && (_jsx(AgentNodePopup, { agentName: selectedAgent.agentName, initialInstructions: selectedAgent.initialInstructions, initialDescription: selectedAgent.initialDescription, isOpen: isPopupOpen, isSaving: isSavingAgent, onClose: handlePopupClose, onSave: handlePopupSave })), _jsx(Backdrop, { open: isDockStreaming, sx: { zIndex: (t) => t.zIndex.modal + 1 }, children: stopState === "confirming" ? (_jsxs(Paper, { elevation: 6, sx: {
|
|
657
|
+
display: "flex",
|
|
658
|
+
flexDirection: "column",
|
|
659
|
+
gap: 2,
|
|
660
|
+
px: 4,
|
|
661
|
+
py: 3,
|
|
662
|
+
borderRadius: 2,
|
|
663
|
+
maxWidth: 420,
|
|
664
|
+
}, children: [_jsx(Typography, { variant: "body1", sx: { fontWeight: "bold" }, children: "Abort changes?" }), _jsx(Typography, { variant: "body2", color: "text.secondary", children: "The in-progress update will be cancelled and discarded. Your network will not be modified." }), _jsxs(Box, { sx: {
|
|
665
|
+
display: "flex",
|
|
666
|
+
gap: 1.5,
|
|
667
|
+
justifyContent: "flex-end",
|
|
668
|
+
}, children: [_jsx(Button, { variant: "outlined", onClick: handleKeepApplying, children: "Keep applying" }), _jsx(Button, { variant: "contained", color: "error", startIcon: _jsx("span", { style: { fontSize: "0.7rem" }, children: "\u25A0" }), onClick: handleStopAndDiscard, children: "Stop & discard" })] })] })) : (_jsxs(Paper, { elevation: 6, sx: {
|
|
669
|
+
display: "flex",
|
|
670
|
+
alignItems: "center",
|
|
671
|
+
gap: 2,
|
|
672
|
+
px: 4,
|
|
673
|
+
py: 2.5,
|
|
674
|
+
borderRadius: 2,
|
|
675
|
+
maxWidth: 480,
|
|
676
|
+
}, children: [_jsx(CircularProgress, { size: 24 }), _jsxs(Box, { sx: { flex: 1 }, children: [_jsx(Typography, { variant: "body1", sx: { fontWeight: "bold" }, children: "Applying changes to network" }), dockPrompt && (_jsx(Typography, { variant: "body2", color: "text.secondary", sx: { mt: 0.25 }, children: dockPrompt }))] }), _jsx(Button, { variant: "outlined", size: "small", startIcon: _jsx("span", { style: { fontSize: "0.65rem" }, children: "\u25A0" }), onClick: handleStopClick, sx: {
|
|
677
|
+
whiteSpace: "nowrap",
|
|
678
|
+
flexShrink: 0,
|
|
679
|
+
color: theme.palette.common.white,
|
|
680
|
+
borderColor: theme.palette.common.white,
|
|
681
|
+
fontWeight: "bold",
|
|
682
|
+
"&:hover": {
|
|
683
|
+
borderColor: theme.palette.error.main,
|
|
684
|
+
color: theme.palette.error.main,
|
|
685
|
+
backgroundColor: alpha(theme.palette.error.main, 0.08),
|
|
686
|
+
},
|
|
687
|
+
}, children: "Stop" })] })) })] }));
|
|
593
688
|
};
|
|
@@ -15,6 +15,7 @@ export interface AgentNodeProps extends Record<string, unknown> {
|
|
|
15
15
|
}
|
|
16
16
|
export declare const NODE_HEIGHT = 100;
|
|
17
17
|
export declare const NODE_WIDTH = 100;
|
|
18
|
+
export declare const FRONTMAN_SIZE_MULTIPLIER = 1.25;
|
|
18
19
|
/**
|
|
19
20
|
* A node representing an agent in the network for use in react-flow.
|
|
20
21
|
* @param props See AgentNodeProps
|
|
@@ -38,6 +38,7 @@ const ZERO_WIDTH_SPACE = "\u200B";
|
|
|
38
38
|
// Node dimensions
|
|
39
39
|
export const NODE_HEIGHT = 100;
|
|
40
40
|
export const NODE_WIDTH = 100;
|
|
41
|
+
export const FRONTMAN_SIZE_MULTIPLIER = 1.25;
|
|
41
42
|
// Icon sizes
|
|
42
43
|
// These are used to set the size of the icons displayed in the agent nodes.
|
|
43
44
|
const AGENT_ICON_SIZE = "2.25rem";
|
|
@@ -158,55 +159,55 @@ export const AgentNode = (props) => {
|
|
|
158
159
|
const glowColor = isLightColor(theme.palette.background.default)
|
|
159
160
|
? theme.palette.common.black
|
|
160
161
|
: theme.palette.common.white;
|
|
161
|
-
const isClickableNode = isEditable;
|
|
162
162
|
const [isHovered, setIsHovered] = useState(false);
|
|
163
163
|
const wrappedAgentName = agentName
|
|
164
164
|
// Allow wrap after underscore
|
|
165
165
|
.replaceAll("_", `_${ZERO_WIDTH_SPACE}`)
|
|
166
166
|
// Allow wrap before capitals in camel/PascalCase (e.g., CustomerSupport -> Customer|Support)
|
|
167
167
|
.replaceAll(/(?<lower>[\da-z])(?<upper>[A-Z])/gu, `$<lower>${ZERO_WIDTH_SPACE}$<upper>`)
|
|
168
|
-
// Also split
|
|
169
|
-
.replaceAll(/(?<
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
168
|
+
// Also split abbreviation->word boundary (e.g., HTTPServer -> HTTP|Server), but not H|T|T|P
|
|
169
|
+
.replaceAll(/(?<abbr>[A-Z])(?<word>[A-Z][a-z])/gu, `$<abbr>${ZERO_WIDTH_SPACE}$<word>`);
|
|
170
|
+
const height = NODE_HEIGHT * (isFrontman ? FRONTMAN_SIZE_MULTIPLIER : 1.0);
|
|
171
|
+
const width = height;
|
|
172
|
+
const getEditButton = () => (_jsx(Tooltip, { title: "Edit", placement: "top", disableInteractive: true, children: _jsx(IconButton, { sx: {
|
|
173
|
+
position: "absolute",
|
|
174
|
+
top: 0,
|
|
175
|
+
right: 0,
|
|
176
|
+
backgroundColor: "rgba(0,0,0,0.45)",
|
|
177
|
+
borderRadius: "50%",
|
|
178
|
+
padding: "3px",
|
|
179
|
+
zIndex: 2,
|
|
180
|
+
cursor: "pointer",
|
|
181
|
+
"&:hover": { backgroundColor: "rgba(0,0,0,0.65)" },
|
|
182
|
+
}, children: _jsx(EditIcon, { id: `${agentId}-edit-icon`, sx: { fontSize: "1rem", color: "white" } }) }) }));
|
|
183
|
+
const getNodeName = () => (_jsx(Tooltip, { id: `${agentId}-tooltip`, title: agentName, placement: "top", disableInteractive: true, children: _jsx(Typography, { id: `${agentId}-name`, sx: {
|
|
184
|
+
backgroundColor: theme.palette.background.paper,
|
|
185
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
186
|
+
borderRadius: 1,
|
|
187
|
+
color: theme.palette.text.primary,
|
|
188
|
+
display: "-webkit-box",
|
|
189
|
+
fontSize: "16px",
|
|
190
|
+
fontWeight: "700",
|
|
191
|
+
marginTop: "0.5rem",
|
|
192
|
+
overflow: "hidden",
|
|
193
|
+
overflowWrap: "anywhere",
|
|
194
|
+
paddingLeft: 0.75,
|
|
195
|
+
paddingRight: 0.75,
|
|
196
|
+
paddingBottom: 0.45,
|
|
197
|
+
paddingTop: 0.45,
|
|
198
|
+
textAlign: "center",
|
|
199
|
+
WebkitBoxOrient: "vertical",
|
|
200
|
+
WebkitLineClamp: 4,
|
|
201
|
+
width,
|
|
202
|
+
zIndex: getZIndex(1, theme),
|
|
203
|
+
}, children: wrappedAgentName }) }));
|
|
204
|
+
const getNode = () => (_jsxs(AnimatedNode, { id: agentId, "data-testid": agentId, glowColor: glowColor, isActive: isActiveAgent, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), sx: {
|
|
205
|
+
backgroundColor,
|
|
206
|
+
color,
|
|
207
|
+
cursor: isEditable ? "pointer" : "grab",
|
|
208
|
+
height,
|
|
209
|
+
width,
|
|
210
|
+
zIndex: getZIndex(1, theme),
|
|
211
|
+
}, children: [getDisplayAsIcon(), isHovered && isEditable && getEditButton(), _jsx(Handle, { id: `${agentId}-left-handle`, position: Position.Left, type: "source", style: { visibility: handleVisibility } }), _jsx(Handle, { id: `${agentId}-right-handle`, position: Position.Right, type: "source", style: { visibility: handleVisibility } }), _jsx(Handle, { id: `${agentId}-top-handle`, position: Position.Top, type: "source", style: { visibility: handleVisibility } }), _jsx(Handle, { id: `${agentId}-bottom-handle`, position: Position.Bottom, type: "source", style: { visibility: handleVisibility } })] }));
|
|
212
|
+
return (_jsxs(_Fragment, { children: [getNode(), getNodeName()] }));
|
|
212
213
|
};
|
|
@@ -19,11 +19,13 @@ limitations under the License.
|
|
|
19
19
|
import dagre from "@dagrejs/dagre";
|
|
20
20
|
import { MarkerType } from "@xyflow/react";
|
|
21
21
|
import cloneDeep from "lodash-es/cloneDeep.js";
|
|
22
|
-
import { NODE_HEIGHT, NODE_WIDTH } from "./AgentNode.js";
|
|
22
|
+
import { FRONTMAN_SIZE_MULTIPLIER, NODE_HEIGHT, NODE_WIDTH } from "./AgentNode.js";
|
|
23
23
|
import { BASE_RADIUS, DEFAULT_FRONTMAN_X_POS, DEFAULT_FRONTMAN_Y_POS, LEVEL_SPACING } from "./const.js";
|
|
24
24
|
import { isEditableAgent } from "./TemporaryNetworks.js";
|
|
25
25
|
import { cleanUpAgentName, KNOWN_MESSAGE_TYPES_FOR_PLASMA } from "../AgentChat/Common/Utils.js";
|
|
26
26
|
export const MAX_GLOBAL_THOUGHT_BUBBLES = 5;
|
|
27
|
+
const FRONTMAN_OFFSET_X = (NODE_WIDTH * (FRONTMAN_SIZE_MULTIPLIER - 1)) / 2;
|
|
28
|
+
const FRONTMAN_OFFSET_Y = (NODE_HEIGHT * (FRONTMAN_SIZE_MULTIPLIER - 1)) / 2;
|
|
27
29
|
export const addThoughtBubbleEdge = (thoughtBubbleEdges, conversationId, edge) => {
|
|
28
30
|
// Add with timestamp for age-based cleanup
|
|
29
31
|
thoughtBubbleEdges.set(conversationId, {
|
|
@@ -194,7 +196,10 @@ isAwaitingLlm, isAgentNetworkDesignerMode, thoughtBubbleEdges, agentIconSuggesti
|
|
|
194
196
|
isEditable: isTemporaryNetwork &&
|
|
195
197
|
isEditableAgent(agentsInNetwork.find((a) => a.origin === nodeId)?.display_as),
|
|
196
198
|
},
|
|
197
|
-
position:
|
|
199
|
+
// position: allow for Frontman being larger
|
|
200
|
+
position: isFrontman
|
|
201
|
+
? { x: DEFAULT_FRONTMAN_X_POS - FRONTMAN_OFFSET_X, y: DEFAULT_FRONTMAN_Y_POS - FRONTMAN_OFFSET_Y }
|
|
202
|
+
: { x, y },
|
|
198
203
|
style: {
|
|
199
204
|
border: "none",
|
|
200
205
|
background: "transparent",
|
|
@@ -279,11 +284,14 @@ isAwaitingLlm, isAgentNetworkDesignerMode, thoughtBubbleEdges, agentIconSuggesti
|
|
|
279
284
|
// Convert dagre's layout to what our flow graph needs
|
|
280
285
|
nodesTmp.forEach((node) => {
|
|
281
286
|
const nodeWithPosition = dagreGraph.node(node.id);
|
|
287
|
+
const isFrontman = frontman?.origin === node.id;
|
|
282
288
|
// We are shifting the dagre node position (anchor=center) to the top left
|
|
283
289
|
// so it matches the React Flow node anchor point (top left).
|
|
290
|
+
const x = nodeWithPosition.x - NODE_WIDTH / 2 - (isFrontman ? FRONTMAN_OFFSET_X : 0);
|
|
291
|
+
const y = nodeWithPosition.y - NODE_HEIGHT / 2 - (isFrontman ? FRONTMAN_OFFSET_Y : 0);
|
|
284
292
|
node.position = {
|
|
285
|
-
x
|
|
286
|
-
y
|
|
293
|
+
x,
|
|
294
|
+
y,
|
|
287
295
|
};
|
|
288
296
|
// Depth is index of x position in xPositions array
|
|
289
297
|
// Create a new data object with updated depth
|