@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.
Files changed (98) hide show
  1. package/README.md +3 -3
  2. package/dist/Theme/Palettes.d.ts +0 -9
  3. package/dist/Theme/Palettes.js +0 -18
  4. package/dist/components/AgentChat/ChatCommon/ChatCommon.d.ts +13 -4
  5. package/dist/components/AgentChat/ChatCommon/ChatCommon.js +131 -38
  6. package/dist/components/AgentChat/ChatCommon/ChatHistory.d.ts +7 -0
  7. package/dist/components/AgentChat/ChatCommon/ChatHistory.js +1 -1
  8. package/dist/components/AgentChat/ChatCommon/Const.d.ts +1 -0
  9. package/dist/components/AgentChat/ChatCommon/Const.js +2 -0
  10. package/dist/components/AgentChat/ChatCommon/ControlButtons.d.ts +5 -3
  11. package/dist/components/AgentChat/ChatCommon/ControlButtons.js +13 -4
  12. package/dist/components/AgentChat/ChatCommon/ConversationTurn.d.ts +5 -5
  13. package/dist/components/AgentChat/ChatCommon/ConversationTurn.js +1 -0
  14. package/dist/components/AgentChat/ChatCommon/FormattedMarkdown.js +3 -0
  15. package/dist/components/AgentChat/ChatCommon/SendButton.js +7 -6
  16. package/dist/components/AgentChat/ChatCommon/SyntaxHighlighterThemes.js +1 -1
  17. package/dist/components/AgentChat/ChatCommon/Thinking.d.ts +1 -0
  18. package/dist/components/AgentChat/ChatCommon/Thinking.js +10 -7
  19. package/dist/components/AgentChat/Common/LlmChatButton.d.ts +0 -2
  20. package/dist/components/AgentChat/Common/LlmChatButton.js +6 -9
  21. package/dist/components/AgentChat/Common/Utils.d.ts +4 -0
  22. package/dist/components/AgentChat/Common/Utils.js +5 -1
  23. package/dist/components/AgentChat/VoiceChat/MicrophoneButton.js +12 -10
  24. package/dist/components/Common/Breadcrumbs.js +1 -1
  25. package/dist/components/Common/Navbar.js +24 -22
  26. package/dist/components/Common/StatusLight.d.ts +9 -0
  27. package/dist/components/Common/StatusLight.js +21 -0
  28. package/dist/components/Common/notification.d.ts +4 -4
  29. package/dist/components/ErrorPage/ErrorBoundary.js +1 -1
  30. package/dist/components/ErrorPage/ErrorPage.d.ts +3 -3
  31. package/dist/components/ErrorPage/ErrorPage.js +4 -3
  32. package/dist/components/Logo/Common.d.ts +4 -0
  33. package/dist/components/Logo/Common.js +8 -0
  34. package/dist/components/Logo/CustomerLogo.d.ts +23 -0
  35. package/dist/components/Logo/CustomerLogo.js +41 -0
  36. package/dist/components/MultiAgentAccelerator/AgentConversations.js +0 -1
  37. package/dist/components/MultiAgentAccelerator/{AgentFlow.d.ts → AgentFlow/AgentFlow.d.ts} +15 -5
  38. package/dist/components/MultiAgentAccelerator/{AgentFlow.js → AgentFlow/AgentFlow.js} +125 -84
  39. package/dist/components/MultiAgentAccelerator/{AgentNode.d.ts → AgentFlow/AgentNode.d.ts} +1 -1
  40. package/dist/components/MultiAgentAccelerator/{AgentNode.js → AgentFlow/AgentNode.js} +26 -30
  41. package/dist/components/MultiAgentAccelerator/AgentFlow/GraphLayouts.d.ts +43 -0
  42. package/dist/components/MultiAgentAccelerator/{GraphLayouts.js → AgentFlow/GraphLayouts.js} +10 -41
  43. package/dist/components/MultiAgentAccelerator/AgentFlow/GraphStructure.d.ts +21 -0
  44. package/dist/components/MultiAgentAccelerator/AgentFlow/GraphStructure.js +27 -0
  45. package/dist/components/MultiAgentAccelerator/AgentFlow/PlasmaEdge.d.ts +7 -0
  46. package/dist/components/MultiAgentAccelerator/{PlasmaEdge.js → AgentFlow/PlasmaEdge.js} +13 -8
  47. package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.d.ts +3 -9
  48. package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +137 -103
  49. package/dist/components/MultiAgentAccelerator/Schema/SlyData.d.ts +17 -0
  50. package/dist/components/MultiAgentAccelerator/Schema/SlyData.js +23 -0
  51. package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.d.ts +0 -5
  52. package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.js +38 -28
  53. package/dist/components/MultiAgentAccelerator/Sidebar/ImportNetworkModal.d.ts +67 -0
  54. package/dist/components/MultiAgentAccelerator/Sidebar/ImportNetworkModal.js +585 -0
  55. package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.d.ts +5 -4
  56. package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.js +77 -168
  57. package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.d.ts +31 -13
  58. package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.js +177 -100
  59. package/dist/components/MultiAgentAccelerator/TemporaryNetworks.d.ts +22 -0
  60. package/dist/components/MultiAgentAccelerator/TemporaryNetworks.js +74 -3
  61. package/dist/components/MultiAgentAccelerator/{ThoughtBubbleEdge.d.ts → ThoughtBubbles/ThoughtBubbleEdge.d.ts} +1 -1
  62. package/dist/components/MultiAgentAccelerator/{ThoughtBubbleOverlay.js → ThoughtBubbles/ThoughtBubbleOverlay.js} +1 -1
  63. package/dist/components/MultiAgentAccelerator/Tour/MainTourSteps.js +15 -8
  64. package/dist/components/MultiAgentAccelerator/const.d.ts +3 -0
  65. package/dist/components/MultiAgentAccelerator/const.js +6 -0
  66. package/dist/components/Settings/ApiKeyInput.js +7 -8
  67. package/dist/components/Settings/InfoTip.d.ts +8 -0
  68. package/dist/components/Settings/InfoTip.js +14 -0
  69. package/dist/components/Settings/SettingsDialog.js +373 -183
  70. package/dist/components/Settings/SettingsRow.d.ts +18 -0
  71. package/dist/components/Settings/SettingsRow.js +35 -0
  72. package/dist/controller/agent/Agent.d.ts +16 -25
  73. package/dist/controller/agent/Agent.js +24 -54
  74. package/dist/controller/agent/IconSuggestions.d.ts +35 -0
  75. package/dist/controller/agent/IconSuggestions.js +85 -0
  76. package/dist/index.d.ts +1 -3
  77. package/dist/index.js +1 -3
  78. package/dist/state/IconSuggestions.d.ts +27 -0
  79. package/dist/state/IconSuggestions.js +50 -0
  80. package/dist/state/Settings.d.ts +97 -6
  81. package/dist/state/Settings.js +110 -8
  82. package/dist/tsconfig.build.tsbuildinfo +1 -1
  83. package/dist/utils/BrowserNavigation.js +2 -0
  84. package/dist/utils/File.d.ts +4 -1
  85. package/dist/utils/File.js +4 -9
  86. package/dist/utils/text.js +3 -7
  87. package/dist/utils/title.js +1 -1
  88. package/package.json +9 -6
  89. package/dist/components/Common/CustomerLogo.d.ts +0 -17
  90. package/dist/components/Common/CustomerLogo.js +0 -47
  91. package/dist/components/Common/MUIAccordion.d.ts +0 -17
  92. package/dist/components/Common/MUIAccordion.js +0 -66
  93. package/dist/components/MultiAgentAccelerator/GraphLayouts.d.ts +0 -36
  94. package/dist/components/MultiAgentAccelerator/PlasmaEdge.d.ts +0 -3
  95. package/dist/utils/useLocalStorage.d.ts +0 -1
  96. package/dist/utils/useLocalStorage.js +0 -55
  97. /package/dist/components/MultiAgentAccelerator/{ThoughtBubbleEdge.js → ThoughtBubbles/ThoughtBubbleEdge.js} +0 -0
  98. /package/dist/components/MultiAgentAccelerator/{ThoughtBubbleOverlay.d.ts → ThoughtBubbles/ThoughtBubbleOverlay.d.ts} +0 -0
@@ -0,0 +1,27 @@
1
+ // "Parent agents" are those that have tools, aka agents with "child agents". A lone single-agent
2
+ // network is treated as its own parent.
3
+ export const getParentAgents = (agents) => agents.length === 1 ? agents : agents.filter((agent) => (agent.tools?.length ?? 0) > 0);
4
+ /**
5
+ * Determines the frontman of an agent network — the single source of truth for "who is the frontman".
6
+ *
7
+ * The frontman is the agent with no parent: a "parent" agent (one that has tools) that is not itself
8
+ * listed as a tool by any other agent. A lone single-agent network is its own frontman. Returns
9
+ * undefined when no agent qualifies (e.g. a fully cyclic network); callers decide how to fall back.
10
+ *
11
+ * Consumed by the graph layouts (to seed the depth-0 node) and by the network import flow.
12
+ */
13
+ export const getFrontman = (agents) => {
14
+ const parentAgents = getParentAgents(agents);
15
+ // Child agents are everything referenced as a tool by a parent.
16
+ const childAgents = new Set(parentAgents.flatMap((agent) => agent.tools ?? []));
17
+ return parentAgents.find((agent) => agent.origin !== undefined && !childAgents.has(agent.origin));
18
+ };
19
+ /**
20
+ * Returns the "origins" (node names) of the _immediate_ parents of a node in the agent network. Grandparents and
21
+ * higher are not included.
22
+ *
23
+ * @param node Node ID for which to find parents
24
+ * @param parentAgents Full list of parent agents in the network
25
+ * @returns The IDs of the immediate parent nodes for the given node or empty array if no parents are found (frontman)
26
+ */
27
+ export const getParents = (node, parentAgents) => parentAgents.filter((agent) => agent.tools.includes(node)).map((parentNode) => parentNode.origin);
@@ -0,0 +1,7 @@
1
+ import { EdgeProps } from "@xyflow/react";
2
+ import { FC } from "react";
3
+ export type PlasmaEdgeProps = {
4
+ readonly maxParticles?: number;
5
+ readonly particlesPerFrame?: number;
6
+ };
7
+ export declare const PlasmaEdge: FC<EdgeProps & PlasmaEdgeProps>;
@@ -16,7 +16,11 @@ limitations under the License.
16
16
  */
17
17
  import { getBezierPath } from "@xyflow/react";
18
18
  import { useEffect, useRef } from "react";
19
- import { useSettingsStore } from "../../state/Settings.js";
19
+ import { useSettingsStore } from "../../../state/Settings.js";
20
+ //#region Constants
21
+ const DEFAULT_MAX_PARTICLES = 250;
22
+ const DEFAULT_PARTICLES_PER_FRAME = 25;
23
+ //#endregion Interfaces and Types
20
24
  const createFunnelParticleOnPath = (pathEl, canvasOffset, baseProgress, plasmaColor) => {
21
25
  const totalLength = pathEl.getTotalLength();
22
26
  const speed = 0.02 + Math.random() * 0.003;
@@ -64,7 +68,7 @@ const createFunnelParticleOnPath = (pathEl, canvasOffset, baseProgress, plasmaCo
64
68
  const isAlive = () => progress * totalLength < totalLength * 0.98;
65
69
  return { update, draw, isAlive };
66
70
  };
67
- export const PlasmaEdge = ({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, }) => {
71
+ export const PlasmaEdge = ({ maxParticles = DEFAULT_MAX_PARTICLES, particlesPerFrame = DEFAULT_PARTICLES_PER_FRAME, sourcePosition, sourceX, sourceY, targetPosition, targetX, targetY, }) => {
68
72
  const canvasRef = useRef(null);
69
73
  const pathRef = useRef(null);
70
74
  const animationRef = useRef(null);
@@ -97,12 +101,10 @@ export const PlasmaEdge = ({ sourceX, sourceY, targetX, targetY, sourcePosition,
97
101
  ctx.setTransform(1, 0, 0, 1, 0, 0);
98
102
  ctx.scale(dpr, dpr);
99
103
  const canvasOffset = { x, y };
100
- const MAX_PARTICLES = 250;
101
- const PARTICLES_PER_FRAME = 25;
102
104
  const animate = () => {
103
105
  ctx.clearRect(0, 0, width, height);
104
- for (let i = 0; i < PARTICLES_PER_FRAME; i += 1) {
105
- if (particles.current.length < MAX_PARTICLES) {
106
+ for (let i = 0; i < particlesPerFrame; i += 1) {
107
+ if (particles.current.length < maxParticles) {
106
108
  const t = Math.random();
107
109
  if (Math.random() < 1 - t) {
108
110
  particles.current.push(createFunnelParticleOnPath(pathEl, canvasOffset, t, plasmaColor));
@@ -118,9 +120,12 @@ export const PlasmaEdge = ({ sourceX, sourceY, targetX, targetY, sourcePosition,
118
120
  };
119
121
  animate();
120
122
  return () => {
121
- if (animationRef.current !== undefined)
123
+ if (animationRef.current !== undefined) {
122
124
  cancelAnimationFrame(animationRef.current);
125
+ animationRef.current = undefined;
126
+ }
127
+ particles.current = [];
123
128
  };
124
- }, [edgePath, width, height, plasmaColor, x, y]);
129
+ }, [edgePath, width, height, plasmaColor, x, y, particlesPerFrame, maxParticles]);
125
130
  return (_jsxs(_Fragment, { children: [_jsx("foreignObject", { id: `foreign-object-${x}-${y}`, width: width, height: height, x: x, y: y, style: { pointerEvents: "none", overflow: "visible" }, children: _jsx("canvas", { id: `canvas-${x}-${y}`, ref: canvasRef }) }), _jsx("path", { id: `path-${edgePath}`, ref: pathRef, d: edgePath, fill: "none", stroke: "none", style: { position: "absolute", visibility: "hidden" } })] }));
126
131
  };
@@ -1,17 +1,11 @@
1
1
  import { FC } from "react";
2
2
  export interface MultiAgentAcceleratorProps {
3
- readonly userInfo: {
4
- userName: string;
5
- userImage: string;
6
- };
7
- readonly backendNeuroSanApiUrl: string;
3
+ readonly username: string;
4
+ readonly defaultNeuroSanUrl: string;
8
5
  }
9
- export declare const GRACE_PERIOD_MS: number;
10
- export declare const SHOW_TOUR_DELAY_MS = 5000;
11
6
  /**
12
7
  * Main Multi-Agent Accelerator component that contains the sidebar, agent flow, and chat components.
13
8
  * @param backendNeuroSanApiUrl Initial URL of the backend Neuro-San API. User can change this in the UI.
14
- * @param darkMode Whether dark mode is enabled.
15
- * @param userInfo Information about the current user, including userName and userImage.
9
+ * @param username Identifier to use for interactions with the backend (for personalization and tracking).
16
10
  */
17
11
  export declare const MultiAgentAccelerator: FC<MultiAgentAcceleratorProps>;
@@ -15,89 +15,59 @@ See the License for the specific language governing permissions and
15
15
  limitations under the License.
16
16
  */
17
17
  import StopCircle from "@mui/icons-material/StopCircle";
18
+ import Backdrop from "@mui/material/Backdrop";
18
19
  import Box from "@mui/material/Box";
20
+ import CircularProgress from "@mui/material/CircularProgress";
19
21
  import Grid from "@mui/material/Grid";
22
+ import Paper from "@mui/material/Paper";
20
23
  import Slide from "@mui/material/Slide";
21
24
  import { useTheme } from "@mui/material/styles";
25
+ import Tooltip from "@mui/material/Tooltip";
22
26
  import Typography from "@mui/material/Typography";
23
27
  import { ReactFlowProvider } from "@xyflow/react";
24
28
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
25
29
  import { useJoyride } from "react-joyride";
26
30
  import { extractConversations } from "./AgentConversations.js";
27
31
  import { getUpdatedAgentCounts } from "./AgentCounts.js";
28
- import { AgentFlow } from "./AgentFlow.js";
32
+ import { AgentFlow } from "./AgentFlow/AgentFlow.js";
29
33
  import { extractAgentNetworkDesignerProgress } from "./AgentNetworkDesigner.js";
30
- import { AGENT_NETWORK_DEFINITION_KEY, AGENT_NETWORK_DESIGNER_ID, AGENT_NETWORK_HOCON, AGENT_NETWORK_NAME_KEY, TRIGGER_APP_TOUR_EVENT_NAME, } from "./const.js";
34
+ import { AGENT_NETWORK_DEFINITION_KEY, AGENT_NETWORK_DESIGNER_ID, AGENT_NETWORK_HOCON, AGENT_NETWORK_NAME_KEY, EXPIRED_NETWORKS_CHECK_INTERVAL_MS, GRACE_PERIOD_MS, SHOW_TOUR_DELAY_MS, TRIGGER_APP_TOUR_EVENT_NAME, } from "./const.js";
35
+ import { ImportNetworkModal } from "./Sidebar/ImportNetworkModal.js";
31
36
  import { Sidebar } from "./Sidebar/Sidebar.js";
32
- import { extractTemporaryNetworksFromMessage, isTemporaryNetwork, mergeNetworks } from "./TemporaryNetworks.js";
33
- import { getAgentFunction, getAgentIconSuggestions, getAgentNetworks, getConnectivity, getNetworkIconSuggestions, sendNetworkDesignerUpdate, } from "../../controller/agent/Agent.js";
37
+ import { extractTemporaryNetworksFromMessage, IMPORT_FAILURE_DETAIL, importNetworkFromJson, isTemporaryNetwork, notifySaveError, streamNetworkDesignerUpsert, } from "./TemporaryNetworks.js";
38
+ import { MAIN_TOUR_STEPS } from "./Tour/MainTourSteps.js";
39
+ import { getAgentFunction, getAgentNetworks, getConnectivity } from "../../controller/agent/Agent.js";
40
+ import { getAgentIconSuggestions, getNetworkIconSuggestions } from "../../controller/agent/IconSuggestions.js";
34
41
  import { useAgentChatHistoryStore } from "../../state/ChatHistory.js";
35
- import { useSettingsStore } from "../../state/Settings.js";
36
42
  import { useTempNetworksStore } from "../../state/TemporaryNetworks.js";
37
43
  import { TourPromptState, useTourStore } from "../../state/Tour.js";
38
- import { useLocalStorage } from "../../utils/useLocalStorage.js";
39
44
  import { getZIndex } from "../../utils/zIndexLayers.js";
40
45
  import { ChatCommon } from "../AgentChat/ChatCommon/ChatCommon.js";
41
- import { SmallLlmChatButton } from "../AgentChat/Common/LlmChatButton.js";
46
+ import { LlmChatButton } from "../AgentChat/Common/LlmChatButton.js";
42
47
  import { isLegacyAgentType } from "../AgentChat/Common/Types.js";
43
48
  import { chatMessageFromChunk, cleanUpAgentName, removeTrailingUuid } from "../AgentChat/Common/Utils.js";
44
49
  import { ConfirmationModal, StyledButton } from "../Common/ConfirmationModal.js";
45
- import { closeNotification, NotificationType, sendNotification } from "../Common/notification.js";
46
- import { MAIN_TOUR_STEPS } from "./Tour/MainTourSteps.js";
50
+ import { MUIAlert } from "../Common/MUIAlert.js";
47
51
  import { MUIDialog } from "../Common/MUIDialog.js";
48
- // Check for expired networks every this many milliseconds
49
- const EXPIRED_NETWORKS_CHECK_INTERVAL_MS = 10 * 1000;
50
- // Display expired temporary networks for this amount of time after they expire so users can see what happened
51
- export const GRACE_PERIOD_MS = 5 * 60 * 1000; // 5 minutes
52
+ import { closeNotification, NotificationType, sendNotification } from "../Common/notification.js";
53
+ import { BYOK } from "./Schema/SlyData.js";
54
+ import { getApiKey, LLM_PROVIDER_API_KEY_FIELD, useSettingsStore } from "../../state/Settings.js";
52
55
  // Animation time for the left and right panels to slide in or out when launching the animation
53
56
  const GROW_ANIMATION_TIME_MS = 800;
54
57
  // Optimization to avoid creating a new empty map on every render
55
58
  const EMPTY_THOUGHT_BUBBLE_EDGES = new Map();
56
- // We show the tour modal after this amount of time so as not to "pounce" on the user when they first open the app
57
- export const SHOW_TOUR_DELAY_MS = 5000;
58
- // #region: Agent-save helpers
59
- /**
60
- * Extracts TemporaryNetworks from a single streamed chunk, merging into `accumulated`.
61
- * Returns `accumulated` unchanged if the chunk yields no reservations or on parse error.
62
- */
63
- const collectNetworksFromChunk = (chunk, updated, accumulated) => {
64
- try {
65
- const chatMessage = chatMessageFromChunk(chunk);
66
- if (!chatMessage)
67
- return accumulated;
68
- // Always use the user's edited definition as the authoritative value.
69
- const converted = extractTemporaryNetworksFromMessage(chatMessage, updated);
70
- if (converted.length === 0)
71
- return accumulated;
72
- return mergeNetworks(accumulated, converted);
73
- }
74
- catch (e) {
75
- console.warn("Failed to process chunk from network designer:", e);
76
- return accumulated;
77
- }
78
- };
79
- /** Logs and notifies about a save error. Suppresses AbortError (user-cancelled). */
80
- const notifySaveError = (agentName, e) => {
81
- if (e instanceof DOMException && e.name === "AbortError")
82
- return;
83
- console.error("Failed to submit agent network update:", e);
84
- const detail = e instanceof DOMException && e.name === "TimeoutError"
85
- ? "The request timed out waiting for the server. Please try again."
86
- : String(e);
87
- sendNotification(NotificationType.error, `Failed to update network "${agentName}".`, detail);
88
- };
89
- // #endregion: Agent-save helpers
90
59
  /**
91
60
  * Main Multi-Agent Accelerator component that contains the sidebar, agent flow, and chat components.
92
61
  * @param backendNeuroSanApiUrl Initial URL of the backend Neuro-San API. User can change this in the UI.
93
- * @param darkMode Whether dark mode is enabled.
94
- * @param userInfo Information about the current user, including userName and userImage.
62
+ * @param username Identifier to use for interactions with the backend (for personalization and tracking).
95
63
  */
96
- export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
64
+ export const MultiAgentAccelerator = ({ defaultNeuroSanUrl, username, }) => {
97
65
  // MUI theme
98
66
  const theme = useTheme();
99
67
  const enableZenMode = useSettingsStore((state) => state.settings.behavior.enableZenMode);
100
68
  const apiKeys = useSettingsStore((state) => state.settings.apiKeys);
69
+ // Display option for agent/network names
70
+ const useNativeNames = useSettingsStore((state) => state.settings.appearance.useNativeNames);
101
71
  // Stores whether are currently awaiting LLM response (for knowing when to show spinners)
102
72
  const [isAwaitingLlm, setIsAwaitingLlm] = useState(false);
103
73
  const [isEditingNetwork, setIsEditingNetwork] = useState(false);
@@ -109,6 +79,8 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
109
79
  const temporaryNetworks = useTempNetworksStore((state) => state.tempNetworks);
110
80
  // Track newly added temp networks so we can highlight them
111
81
  const [newlyAddedTemporaryNetworks, setNewlyAddedTemporaryNetworks] = useState(new Set());
82
+ // True while a file import is in-flight (after modal confirm, before the new network appears)
83
+ const [isImporting, setIsImporting] = useState(false);
112
84
  const [networkIconSuggestions, setNetworkIconSuggestions] = useState({});
113
85
  const [agentsInNetwork, setAgentsInNetwork] = useState([]);
114
86
  const [sampleQueries, setSampleQueries] = useState([]);
@@ -118,11 +90,10 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
118
90
  const [agentIconSuggestions, setAgentIconSuggestions] = useState(null);
119
91
  const [selectedNetwork, setSelectedNetwork] = useState(null);
120
92
  const [networkDescription, setNetworkDescription] = useState("");
121
- const networkDisplayName = useMemo(() => cleanUpAgentName(removeTrailingUuid(selectedNetwork)), [selectedNetwork]);
122
- const [providerKeysRequired, setProviderKeysRequired] = useState(new Set());
123
- const [customURLLocalStorage, setCustomURLLocalStorage] = useLocalStorage("customAgentNetworkURL", null);
124
- // An extra set of quotes is making it in the string in local storage.
125
- const [neuroSanURL, setNeuroSanURL] = useState(customURLLocalStorage?.replaceAll('"', "") || backendNeuroSanApiUrl);
93
+ const networkDisplayName = useMemo(() => (useNativeNames ? selectedNetwork : cleanUpAgentName(removeTrailingUuid(selectedNetwork))), [selectedNetwork, useNativeNames]);
94
+ // LLM providers for which BYOK keys are supported by the current network
95
+ const [supportedByokProviders, setSupportedByokProviders] = useState(new Set());
96
+ const neuroSanURL = useSettingsStore((state) => state.settings.externalServices.neuroSanUrl) ?? defaultNeuroSanUrl;
126
97
  // Tracks how many times each agent has been involved in the conversation
127
98
  const [agentCounts, setAgentCounts] = useState(new Map());
128
99
  // Common function to change the selected network and reset related state
@@ -136,12 +107,9 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
136
107
  // State to hold thought bubble edges - avoids duplicates across layout recalculations
137
108
  const [thoughtBubbleEdges, setThoughtBubbleEdges] = useState(new Map());
138
109
  const [confirmationModalOpen, setConfirmationModalOpen] = useState(false);
110
+ const [importModalOpen, setImportModalOpen] = useState(false);
139
111
  const [tourModalOpen, setTourModalOpen] = useState(false);
140
112
  const [haveShownTourModal, setHaveShownTourModal] = useState(false);
141
- const customURLCallback = useCallback((url) => {
142
- setNeuroSanURL(url || backendNeuroSanApiUrl);
143
- setCustomURLLocalStorage(url === "" ? null : url);
144
- }, [backendNeuroSanApiUrl, setCustomURLLocalStorage]);
145
113
  // Memoized key for agent names to trigger icon suggestion updates when the set of agents changes, not just
146
114
  // when sorting/other operations on the agents list
147
115
  const agentNamesKey = useMemo(() => agentsInNetwork
@@ -209,16 +177,14 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
209
177
  * Builds the API keys object to be sent as extraSlyData with each request, based on the LLM providers required
210
178
  * by the currently selected network. Only includes keys for providers that are required.
211
179
  */
212
- const getApiKeys = () => {
213
- const llmConfig = {};
214
- if (providerKeysRequired.has("OpenAI")) {
215
- llmConfig["openai_api_key"] = apiKeys["OpenAI"];
216
- }
217
- if (providerKeysRequired.has("Anthropic")) {
218
- llmConfig["anthropic_api_key"] = apiKeys["Anthropic"];
219
- }
220
- return { llm_config: llmConfig };
221
- };
180
+ const getApiKeys = () => ({
181
+ llm_config: Object.fromEntries([...supportedByokProviders]
182
+ .map((provider) => [
183
+ LLM_PROVIDER_API_KEY_FIELD[provider],
184
+ getApiKey(apiKeys, provider),
185
+ ])
186
+ .filter((entry) => Boolean(entry[1]))),
187
+ });
222
188
  /**
223
189
  * Builds the extraSlyData object to be sent with each request, including information for Agent Network Designer
224
190
  * and (if required) API keys for LLM providers.
@@ -245,7 +211,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
245
211
  return undefined;
246
212
  };
247
213
  // Whether any API keys are required
248
- const anyApiKeysRequired = providerKeysRequired.size > 0;
214
+ const anyApiKeysRequired = supportedByokProviders.size > 0;
249
215
  // Build base extraSlyData
250
216
  const baseExtraSlyData = buildExtraSlyData();
251
217
  // Add API keys to extraSlyData if needed, merging with baseExtraSlyData if it exists
@@ -260,7 +226,33 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
260
226
  chatRef.current?.handleStop();
261
227
  resetState();
262
228
  }, [resetState]);
263
- const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
229
+ /**
230
+ * Maps an API key name to the corresponding LLM provider
231
+ */
232
+ const apiKeyToProvider = useCallback((key) => {
233
+ switch (key) {
234
+ case "openai_api_key":
235
+ return "OpenAI";
236
+ case "anthropic_api_key":
237
+ return "Anthropic";
238
+ default:
239
+ return null;
240
+ }
241
+ }, []);
242
+ /**
243
+ * Given a SlyData schema, returns the set of LLM providers that are supported by the agent network.
244
+ * @note Semantics are "oneOf": a key must be supplied for at least one of the named providers
245
+ */
246
+ const getSupportedLlmProviders = useCallback((schema) => {
247
+ const parsed = BYOK.safeParse(schema);
248
+ if (!parsed.success || !parsed.data.required?.includes("llm_config")) {
249
+ return new Set();
250
+ }
251
+ const providerKeys = Object.keys(parsed.data.properties?.llm_config?.properties ?? {});
252
+ return new Set(providerKeys
253
+ .map((key) => apiKeyToProvider(key))
254
+ .filter((provider) => provider !== null));
255
+ }, [apiKeyToProvider]);
264
256
  useEffect(() => {
265
257
  ;
266
258
  (async () => {
@@ -281,23 +273,14 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
281
273
  const fetchAgentDetails = async () => {
282
274
  // It is a Neuro-san agent, so get the function and connectivity info
283
275
  try {
284
- const agentFunction = await getAgentFunction(neuroSanURL, selectedNetwork, userInfo.userName);
276
+ // Reset before fetching
277
+ setNetworkDescription("");
278
+ setSupportedByokProviders(new Set());
279
+ // Get agent function from server
280
+ const agentFunction = await getAgentFunction(neuroSanURL, selectedNetwork, username);
285
281
  setNetworkDescription(agentFunction?.function?.description || "");
286
282
  const schema = agentFunction?.function?.sly_data_schema;
287
- const schemaProperties = isRecord(schema) ? schema["properties"] : undefined;
288
- const llmConfig = isRecord(schemaProperties) ? schemaProperties["llm_config"] : undefined;
289
- const llmConfigRequired = isRecord(llmConfig) ? llmConfig["required"] : undefined;
290
- setProviderKeysRequired(new Set((Array.isArray(llmConfigRequired) ? llmConfigRequired : []).flatMap((key) => {
291
- if (key === "openai_api_key") {
292
- return ["OpenAI"];
293
- }
294
- if (key === "anthropic_api_key") {
295
- return ["Anthropic"];
296
- }
297
- console.warn(`Unknown API key requirement "${key}" for network ${selectedNetwork}. Skipping.`);
298
- // Will get dropped by flatMap
299
- return [];
300
- })));
283
+ setSupportedByokProviders(getSupportedLlmProviders(schema));
301
284
  }
302
285
  catch (e) {
303
286
  console.warn(`Unable to get agent details for network ${selectedNetwork}:`, e);
@@ -308,7 +291,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
308
291
  if (selectedNetwork && !isLegacyAgentType(selectedNetwork)) {
309
292
  void fetchAgentDetails();
310
293
  }
311
- }, [neuroSanURL, selectedNetwork, userInfo.userName]);
294
+ }, [getSupportedLlmProviders, neuroSanURL, selectedNetwork, username]);
312
295
  useEffect(() => {
313
296
  ;
314
297
  (async () => {
@@ -329,7 +312,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
329
312
  (async () => {
330
313
  if (selectedNetwork) {
331
314
  try {
332
- const connectivity = await getConnectivity(neuroSanURL, selectedNetwork, userInfo.userName);
315
+ const connectivity = await getConnectivity(neuroSanURL, selectedNetwork, username);
333
316
  const agentsInNetworkSorted = [...connectivity.connectivity_info].sort((a, b) => a?.origin.localeCompare(b?.origin));
334
317
  setAgentsInNetwork(agentsInNetworkSorted);
335
318
  const sampleQueriesTmp = connectivity?.metadata?.["sample_queries"];
@@ -352,7 +335,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
352
335
  setAgentsInNetwork([]);
353
336
  }
354
337
  })();
355
- }, [networkDisplayName, neuroSanURL, selectedNetwork, userInfo.userName]);
338
+ }, [networkDisplayName, neuroSanURL, selectedNetwork, username]);
356
339
  useEffect(() => {
357
340
  ;
358
341
  (async () => {
@@ -474,10 +457,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
474
457
  */
475
458
  const onSaveAgent = useCallback(async (agentName, updated, agentNetworkName, signal) => {
476
459
  try {
477
- let newNetworks = [];
478
- await sendNetworkDesignerUpdate(neuroSanURL, signal, agentName, updated, agentNetworkName, userInfo.userName, (chunk) => {
479
- newNetworks = collectNetworksFromChunk(chunk, updated, newNetworks);
480
- });
460
+ const newNetworks = await streamNetworkDesignerUpsert(neuroSanURL, signal, agentName, updated, agentNetworkName, username);
481
461
  if (newNetworks.length === 0) {
482
462
  sendNotification(NotificationType.error, `Failed to update network "${agentName}".`, "The network designer did not return a reservation. Please try again.");
483
463
  return;
@@ -499,7 +479,36 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
499
479
  catch (e) {
500
480
  notifySaveError(agentName, e);
501
481
  }
502
- }, [neuroSanURL, userInfo.userName, selectedNetwork]);
482
+ }, [neuroSanURL, username, selectedNetwork]);
483
+ /**
484
+ * Handles an import from the ImportNetworkModal: converts the JSON content to a
485
+ * network definition, streams it through the network designer to obtain a reservation,
486
+ * then upserts the result into the temporary-networks store and navigates to the new network.
487
+ */
488
+ const handleImportNetwork = useCallback(async (agentNetworkName, content) => {
489
+ setIsImporting(true);
490
+ try {
491
+ const result = await importNetworkFromJson(content, agentNetworkName, neuroSanURL, username);
492
+ if ("failure" in result) {
493
+ sendNotification(NotificationType.error, `Failed to import "${agentNetworkName}".`, IMPORT_FAILURE_DETAIL[result.failure]);
494
+ return;
495
+ }
496
+ useTempNetworksStore.getState().upsertTempNetworks(result.networks);
497
+ // An import defines a single network, so the designer returns one reservation. Highlight and
498
+ // navigate to it; any further entries (none expected) are still upserted above.
499
+ const newNetworkName = result.networks[0]?.agentInfo.agent_name;
500
+ if (newNetworkName) {
501
+ setNewlyAddedTemporaryNetworks(new Set([newNetworkName]));
502
+ changeSelectedNetwork(newNetworkName);
503
+ }
504
+ }
505
+ catch (e) {
506
+ notifySaveError(agentNetworkName, e);
507
+ }
508
+ finally {
509
+ setIsImporting(false);
510
+ }
511
+ }, [changeSelectedNetwork, neuroSanURL, username]);
503
512
  const onStreamingStarted = useCallback(() => {
504
513
  // Reset agent counts
505
514
  setAgentCounts(new Map());
@@ -519,7 +528,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
519
528
  }, [resetState]);
520
529
  const handleDeleteNetwork = (networkId, isExpired) => {
521
530
  if (isExpired) {
522
- // It's expired so just delete it without confirmation
531
+ // It's expired, so just delete it without confirmation
523
532
  const tempNetworksWithoutThisOne = temporaryNetworks.filter((network) => network.agentInfo.agent_name !== networkId);
524
533
  useTempNetworksStore.getState().setTempNetworks(tempNetworksWithoutThisOne);
525
534
  useAgentChatHistoryStore.getState().resetHistory(networkId);
@@ -563,14 +572,17 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
563
572
  }
564
573
  }, [tourRequested, selectedNetwork, agentsInNetwork, networks, controls, setTourStatus]);
565
574
  const getMissingApiKeys = () => {
566
- return providerKeysRequired.size > 0 ? [...providerKeysRequired].filter((provider) => !apiKeys?.[provider]) : [];
575
+ // Calculate intersection of what we have (apiKeys) and what is required (providerKeysRequired)
576
+ const intersection = new Set([...supportedByokProviders].filter((provider) => getApiKey(apiKeys, provider)));
577
+ return intersection.size === 0 ? supportedByokProviders : new Set();
567
578
  };
579
+ const hasMissingApiKeys = getMissingApiKeys().size > 0;
568
580
  const getLeftPanel = () => {
569
581
  return (_jsx(Slide, { id: "multi-agent-accelerator-grid-sidebar-slide", in: !enableZenMode || !isAwaitingLlm, direction: "right", timeout: GROW_ANIMATION_TIME_MS, onExited: () => {
570
582
  setIsStreaming(true);
571
583
  }, children: _jsx(Grid, { id: "multi-agent-accelerator-grid-sidebar", size: enableZenMode && isStreaming ? 0 : 3.25, sx: {
572
584
  height: "100%",
573
- }, children: _jsx(Sidebar, { customURLLocalStorage: customURLLocalStorage, customURLCallback: customURLCallback, id: "multi-agent-accelerator-sidebar", isAwaitingLlm: isAwaitingLlm, networks: networks, networkIconSuggestions: networkIconSuggestions, newlyAddedTemporaryNetworks: newlyAddedTemporaryNetworks, onEditNetwork: handleEditNetwork, onDeleteNetwork: handleDeleteNetwork, setSelectedNetwork: (newNetwork) => changeSelectedNetwork(newNetwork), temporaryNetworks: temporaryNetworks }) }) }));
585
+ }, children: _jsx(Sidebar, { id: "multi-agent-accelerator-sidebar", isAwaitingLlm: isAwaitingLlm, isImporting: isImporting, networkIconSuggestions: networkIconSuggestions, networks: networks, neuroSanServerURL: neuroSanURL, newlyAddedTemporaryNetworks: newlyAddedTemporaryNetworks, onDeleteNetwork: handleDeleteNetwork, onEditNetwork: handleEditNetwork, onImportClick: () => setImportModalOpen(true), setSelectedNetwork: (newNetwork) => changeSelectedNetwork(newNetwork), temporaryNetworks: temporaryNetworks }) }) }));
574
586
  };
575
587
  const getCenterPanel = () => {
576
588
  return (_jsx(Grid, { id: "multi-agent-accelerator-grid-agent-flow", size: enableZenMode && isStreaming ? 18 : 8.25, sx: {
@@ -583,7 +595,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
583
595
  height: "100%",
584
596
  maxWidth: 1000,
585
597
  margin: "0 auto",
586
- }, children: _jsx(AgentFlow, { agentCounts: agentCounts, agentsInNetwork: agentsInNetwork, agentIconSuggestions: agentIconSuggestions, id: "multi-agent-accelerator-agent-flow", currentConversations: currentConversations, currentUser: userInfo.userName, isAwaitingLlm: isAwaitingLlm, isEditMode: isEditingNetwork, isStreaming: isStreaming, isSelectedNetworkTemporary: isSelectedNetworkTemporary, networkDisplayName: selectedNetwork || undefined, networkId: isSelectedNetworkTemporary ? selectedNetwork : undefined, neuroSanURL: neuroSanURL, onEnterEditMode: () => setIsEditingNetwork(true), onExitEditMode: () => setIsEditingNetwork(false), onNetworkReplaced: (_old, newId) => changeSelectedNetwork(newId), onSaveAgent: onSaveAgent, thoughtBubbleEdges: thoughtBubbleEdges, setThoughtBubbleEdges: setThoughtBubbleEdges }, "multi-agent-accelerator-agent-flow") }) }) }));
598
+ }, children: _jsx(AgentFlow, { agentCounts: agentCounts, agentsInNetwork: agentsInNetwork, agentIconSuggestions: agentIconSuggestions, id: "multi-agent-accelerator-agent-flow", currentConversations: currentConversations, currentUser: username, isAwaitingLlm: isAwaitingLlm, isEditMode: isEditingNetwork, isStreaming: isStreaming, isSelectedNetworkTemporary: isSelectedNetworkTemporary, networkDisplayName: networkDisplayName || "", networkId: isSelectedNetworkTemporary ? selectedNetwork : "", neuroSanURL: neuroSanURL, onEnterEditMode: () => setIsEditingNetwork(true), onExitEditMode: () => setIsEditingNetwork(false), onNetworkReplaced: (_old, newId) => changeSelectedNetwork(newId), onSaveAgent: onSaveAgent, thoughtBubbleEdges: thoughtBubbleEdges, setThoughtBubbleEdges: setThoughtBubbleEdges }, "multi-agent-accelerator-agent-flow") }) }) }));
587
599
  };
588
600
  const getRightPanel = () => {
589
601
  return (_jsx(Slide, { id: "multi-agent-accelerator-grid-agent-chat-common-slide", in: !enableZenMode || !isAwaitingLlm, direction: "left", timeout: GROW_ANIMATION_TIME_MS, onExited: () => {
@@ -592,17 +604,21 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
592
604
  height: "100%",
593
605
  }, children: _jsx(ChatCommon, { agentPlaceholders: {
594
606
  [AGENT_NETWORK_DESIGNER_ID]: "Describe in plain language the network you would like to build.",
595
- }, currentUser: userInfo.userName, customAgentGreetings: {
607
+ }, currentUser: username, customAgentGreetings: {
596
608
  [AGENT_NETWORK_DESIGNER_ID]: "Let's build a network together!",
597
- }, extraSlyData: extraSlyData, id: "agent-network-ui", isAwaitingLlm: isAwaitingLlm, missingApiKeys: getMissingApiKeys(), networkDescription: networkDescription, neuroSanURL: neuroSanURL, onChunkReceived: onChunkReceived, onStreamingComplete: onStreamingComplete, onStreamingStarted: onStreamingStarted, ref: chatRef, sampleQueries: sampleQueries, setIsAwaitingLlm: setIsAwaitingLlm, selectedNetwork: selectedNetwork }, selectedNetwork ?? "no-network") }) }));
609
+ }, extraSlyData: extraSlyData, id: "agent-network-ui", isAwaitingLlm: isAwaitingLlm, hasMissingApiKeys: hasMissingApiKeys, networkDescription: networkDescription, neuroSanURL: neuroSanURL, onChunkReceived: onChunkReceived, onStreamingComplete: onStreamingComplete, onStreamingStarted: onStreamingStarted, ref: chatRef, sampleQueries: sampleQueries, setIsAwaitingLlm: setIsAwaitingLlm, selectedNetwork: selectedNetwork, setSelectedNetwork: changeSelectedNetwork }, selectedNetwork ?? "no-network") }) }));
598
610
  };
599
611
  const getStopButton = () => {
600
612
  return (_jsx(_Fragment, { children: isAwaitingLlm && enableZenMode && (_jsx(Box, { id: "stop-button-container", sx: {
601
613
  position: "absolute",
602
614
  bottom: "1rem",
603
615
  right: "1rem",
604
- zIndex: 10,
605
- }, children: _jsx(SmallLlmChatButton, { "aria-label": "Stop", disabled: !isAwaitingLlm, id: "stop-output-button", onClick: handleExternalStop, posBottom: 8, posRight: 23, children: _jsx(StopCircle, { fontSize: "small", id: "stop-button-icon", sx: { color: "var(--bs-white)" } }) }) })) }));
616
+ zIndex: getZIndex(2, theme),
617
+ }, children: _jsx(Tooltip, { title: "Stop response (Esc)", children: _jsx(LlmChatButton, { "aria-label": "Stop", id: "stop-output-button", onClick: handleExternalStop, sx: {
618
+ "&:hover": {
619
+ backgroundColor: "error.main",
620
+ },
621
+ }, children: _jsx(StopCircle, { fontSize: "large", id: "stop-button-icon" }) }) }) })) }));
606
622
  };
607
623
  const getDeleteNetworkConfirmationModal = () => confirmationModalOpen ? (_jsx(ConfirmationModal, { id: "delete-network-confirmation-modal", content: `The network "${cleanUpAgentName(removeTrailingUuid(networkToBeDeleted))}" will be deleted. ` +
608
624
  "This action cannot be undone. Are you sure you want to proceed?", handleCancel: () => {
@@ -619,6 +635,17 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
619
635
  setNetworkToBeDeleted(null);
620
636
  setConfirmationModalOpen(false);
621
637
  }, title: "Delete Network" })) : null;
638
+ const getImportNetworkModal = () => (_jsx(ImportNetworkModal, { existingNetworkNames: temporaryNetworks.map((n) => n.agentNetworkName), isOpen: importModalOpen, onClose: () => setImportModalOpen(false), onImport: handleImportNetwork }));
639
+ // Blocking overlay shown while an imported network is being created on the backend.
640
+ const getImportBackdrop = () => (_jsx(Backdrop, { id: "multi-agent-accelerator-import-backdrop", "data-testid": "multi-agent-accelerator-import-backdrop", open: isImporting, sx: { zIndex: getZIndex(3, theme) }, children: _jsxs(Paper, { elevation: 6, role: "status", "aria-live": "polite", sx: {
641
+ display: "flex",
642
+ alignItems: "center",
643
+ gap: 2,
644
+ px: 4,
645
+ py: 2.5,
646
+ borderRadius: 2,
647
+ maxWidth: 480,
648
+ }, children: [_jsx(CircularProgress, { id: "multi-agent-accelerator-import-spinner", size: 24 }), _jsx(Typography, { id: "multi-agent-accelerator-import-title", variant: "body1", sx: { fontWeight: "bold" }, children: "Importing network..." })] }) }));
622
649
  const getTourModal = () => tourModalOpen && (_jsx(MUIDialog, { contentSx: { fontSize: "0.8rem", minWidth: "550px", paddingTop: "0" }, footer: _jsxs(_Fragment, { children: [_jsx(StyledButton, { id: "tour-dont-show-again", onClick: () => {
623
650
  setTourStatus(TourPromptState.DontShowAgain);
624
651
  dismissTourModal();
@@ -660,7 +687,14 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
660
687
  opacity: "95%",
661
688
  width: "100%",
662
689
  }, 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..." }))] }) }) }));
663
- return (_jsxs(_Fragment, { children: [Tour, getTourModal(), getProgressPopper(), getDeleteNetworkConfirmationModal(), _jsxs(Grid, { id: "multi-agent-accelerator-grid", container: true, columns: 18, sx: {
690
+ const getMissingApiKeysAlert = () => hasMissingApiKeys && (_jsx(MUIAlert, { closeable: false, id: "llm-chat-missing-api-keys-alert", severity: "warning", sx: {
691
+ my: 1.5,
692
+ "& .MuiAlert-message": {
693
+ width: "100%",
694
+ textAlign: "center",
695
+ },
696
+ }, children: _jsxs(Typography, { sx: { fontSize: "larger" }, children: ["API key(s) required for at least one of these providers:", " ", _jsx("strong", { children: [...getMissingApiKeys()].join(", ") }), ". Please add the required key(s) in \"Settings\" to use this Network."] }) }));
697
+ return (_jsxs(_Fragment, { children: [getMissingApiKeysAlert(), Tour, getTourModal(), getProgressPopper(), getDeleteNetworkConfirmationModal(), getImportNetworkModal(), getImportBackdrop(), _jsxs(Grid, { id: "multi-agent-accelerator-grid", container: true, columns: 18, sx: {
664
698
  display: "flex",
665
699
  flex: 1,
666
700
  height: "85%",
@@ -0,0 +1,17 @@
1
+ import * as z from "zod";
2
+ /**
3
+ * Zod schema for sly_data BYOK structure
4
+ */
5
+ export declare const BYOK: z.ZodObject<{
6
+ type: z.ZodOptional<z.ZodString>;
7
+ required: z.ZodOptional<z.ZodTuple<[z.ZodLiteral<"llm_config">], null>>;
8
+ properties: z.ZodOptional<z.ZodObject<{
9
+ llm_config: z.ZodOptional<z.ZodObject<{
10
+ type: z.ZodOptional<z.ZodString>;
11
+ properties: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
12
+ type: z.ZodOptional<z.ZodString>;
13
+ description: z.ZodOptional<z.ZodString>;
14
+ }, z.core.$loose>>>;
15
+ }, z.core.$loose>>;
16
+ }, z.core.$loose>>;
17
+ }, z.core.$loose>;
@@ -0,0 +1,23 @@
1
+ import * as z from "zod";
2
+ /**
3
+ * Zod schema for sly_data BYOK structure
4
+ */
5
+ export const BYOK = z.looseObject({
6
+ type: z.string().optional(),
7
+ required: z.tuple([z.literal("llm_config")]).optional(),
8
+ properties: z
9
+ .looseObject({
10
+ llm_config: z
11
+ .looseObject({
12
+ type: z.string().optional(),
13
+ properties: z
14
+ .record(z.string(), z.looseObject({
15
+ type: z.string().optional(),
16
+ description: z.string().optional(),
17
+ }))
18
+ .optional(),
19
+ })
20
+ .optional(),
21
+ })
22
+ .optional(),
23
+ });
@@ -1,13 +1,8 @@
1
1
  import { TreeItemProps } from "@mui/x-tree-view/TreeItem";
2
2
  import { FC } from "react";
3
- import { NodeIndex } from "./TreeBuilder.js";
4
3
  export interface AgentNetworkNodeProps extends TreeItemProps {
5
- readonly nodeIndex: NodeIndex;
6
4
  readonly onDeleteNetwork?: (network: string, isExpired: boolean) => void;
7
5
  readonly onEditNetwork?: (network: string) => void;
8
- readonly networkIconSuggestions: Record<string, string>;
9
- readonly temporaryNetworkExpirationTimes?: Record<string, Date>;
10
- readonly temporaryNetworkHoconStrings?: Record<string, string | null>;
11
6
  }
12
7
  /**
13
8
  * Custom Tree Item for MUI RichTreeView to display agent networks with tags