@cognizant-ai-lab/ui-common 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Theme/Palettes.d.ts +0 -9
- package/dist/Theme/Palettes.js +0 -18
- package/dist/components/AgentChat/ChatCommon/ChatCommon.d.ts +11 -7
- package/dist/components/AgentChat/ChatCommon/ChatCommon.js +119 -90
- 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 +1 -1
- package/dist/components/AgentChat/ChatCommon/ControlButtons.js +7 -4
- 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/VoiceChat/MicrophoneButton.js +12 -10
- package/dist/components/ChatBot/ChatBot.d.ts +0 -4
- package/dist/components/ChatBot/ChatBot.js +2 -2
- 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/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.js +85 -53
- package/dist/components/MultiAgentAccelerator/AgentNode.js +23 -27
- package/dist/components/MultiAgentAccelerator/GraphLayouts.d.ts +17 -10
- package/dist/components/MultiAgentAccelerator/GraphLayouts.js +4 -6
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.d.ts +3 -9
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +102 -47
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.d.ts +0 -5
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.js +30 -25
- package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.d.ts +3 -4
- package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.js +84 -168
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.d.ts +30 -13
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.js +157 -100
- package/dist/components/MultiAgentAccelerator/Tour/MainTourSteps.js +10 -8
- package/dist/components/MultiAgentAccelerator/const.d.ts +2 -0
- package/dist/components/MultiAgentAccelerator/const.js +4 -0
- package/dist/components/Settings/ApiKeyInput.d.ts +16 -0
- package/dist/components/Settings/ApiKeyInput.js +69 -0
- package/dist/components/Settings/InfoTip.d.ts +8 -0
- package/dist/components/Settings/InfoTip.js +14 -0
- package/dist/components/Settings/SettingsDialog.js +379 -178
- package/dist/components/Settings/SettingsRow.d.ts +18 -0
- package/dist/components/Settings/SettingsRow.js +35 -0
- package/dist/controller/agent/Agent.d.ts +3 -20
- package/dist/controller/agent/Agent.js +9 -43
- package/dist/controller/agent/IconSuggestions.d.ts +35 -0
- package/dist/controller/agent/IconSuggestions.js +85 -0
- package/dist/controller/llm/Providers.d.ts +2 -0
- package/dist/controller/llm/Providers.js +41 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -2
- package/dist/state/IconSuggestions.d.ts +27 -0
- package/dist/state/IconSuggestions.js +50 -0
- package/dist/state/Settings.d.ts +19 -3
- package/dist/state/Settings.js +24 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/title.js +1 -1
- package/package.json +5 -1
- package/dist/components/Common/CustomerLogo.d.ts +0 -17
- package/dist/components/Common/CustomerLogo.js +0 -49
- package/dist/components/Common/MUIAccordion.d.ts +0 -17
- package/dist/components/Common/MUIAccordion.js +0 -66
- package/dist/utils/useLocalStorage.d.ts +0 -1
- package/dist/utils/useLocalStorage.js +0 -55
|
@@ -19,6 +19,7 @@ import Box from "@mui/material/Box";
|
|
|
19
19
|
import Grid from "@mui/material/Grid";
|
|
20
20
|
import Slide from "@mui/material/Slide";
|
|
21
21
|
import { useTheme } from "@mui/material/styles";
|
|
22
|
+
import Tooltip from "@mui/material/Tooltip";
|
|
22
23
|
import Typography from "@mui/material/Typography";
|
|
23
24
|
import { ReactFlowProvider } from "@xyflow/react";
|
|
24
25
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
@@ -27,18 +28,18 @@ import { extractConversations } from "./AgentConversations.js";
|
|
|
27
28
|
import { getUpdatedAgentCounts } from "./AgentCounts.js";
|
|
28
29
|
import { AgentFlow } from "./AgentFlow.js";
|
|
29
30
|
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";
|
|
31
|
+
import { AGENT_NETWORK_DEFINITION_KEY, AGENT_NETWORK_DESIGNER_ID, AGENT_NETWORK_HOCON, AGENT_NETWORK_NAME_KEY, GRACE_PERIOD_MS, SHOW_TOUR_DELAY_MS, TRIGGER_APP_TOUR_EVENT_NAME, } from "./const.js";
|
|
31
32
|
import { Sidebar } from "./Sidebar/Sidebar.js";
|
|
32
33
|
import { extractTemporaryNetworksFromMessage, isTemporaryNetwork, mergeNetworks } from "./TemporaryNetworks.js";
|
|
33
|
-
import { getAgentFunction,
|
|
34
|
+
import { getAgentFunction, getAgentNetworks, getConnectivity, sendNetworkDesignerUpdate, } from "../../controller/agent/Agent.js";
|
|
35
|
+
import { getAgentIconSuggestions, getNetworkIconSuggestions } from "../../controller/agent/IconSuggestions.js";
|
|
34
36
|
import { useAgentChatHistoryStore } from "../../state/ChatHistory.js";
|
|
35
37
|
import { useSettingsStore } from "../../state/Settings.js";
|
|
36
38
|
import { useTempNetworksStore } from "../../state/TemporaryNetworks.js";
|
|
37
39
|
import { TourPromptState, useTourStore } from "../../state/Tour.js";
|
|
38
|
-
import { useLocalStorage } from "../../utils/useLocalStorage.js";
|
|
39
40
|
import { getZIndex } from "../../utils/zIndexLayers.js";
|
|
40
41
|
import { ChatCommon } from "../AgentChat/ChatCommon/ChatCommon.js";
|
|
41
|
-
import {
|
|
42
|
+
import { LlmChatButton } from "../AgentChat/Common/LlmChatButton.js";
|
|
42
43
|
import { isLegacyAgentType } from "../AgentChat/Common/Types.js";
|
|
43
44
|
import { chatMessageFromChunk, cleanUpAgentName, removeTrailingUuid } from "../AgentChat/Common/Utils.js";
|
|
44
45
|
import { ConfirmationModal, StyledButton } from "../Common/ConfirmationModal.js";
|
|
@@ -47,14 +48,10 @@ import { MAIN_TOUR_STEPS } from "./Tour/MainTourSteps.js";
|
|
|
47
48
|
import { MUIDialog } from "../Common/MUIDialog.js";
|
|
48
49
|
// Check for expired networks every this many milliseconds
|
|
49
50
|
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
51
|
// Animation time for the left and right panels to slide in or out when launching the animation
|
|
53
52
|
const GROW_ANIMATION_TIME_MS = 800;
|
|
54
53
|
// Optimization to avoid creating a new empty map on every render
|
|
55
54
|
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
55
|
// #region: Agent-save helpers
|
|
59
56
|
/**
|
|
60
57
|
* Extracts TemporaryNetworks from a single streamed chunk, merging into `accumulated`.
|
|
@@ -76,7 +73,7 @@ const collectNetworksFromChunk = (chunk, updated, accumulated) => {
|
|
|
76
73
|
return accumulated;
|
|
77
74
|
}
|
|
78
75
|
};
|
|
79
|
-
/** Logs and notifies about a save error. Suppresses AbortError (user-
|
|
76
|
+
/** Logs and notifies about a save error. Suppresses AbortError (user-canceled). */
|
|
80
77
|
const notifySaveError = (agentName, e) => {
|
|
81
78
|
if (e instanceof DOMException && e.name === "AbortError")
|
|
82
79
|
return;
|
|
@@ -90,13 +87,15 @@ const notifySaveError = (agentName, e) => {
|
|
|
90
87
|
/**
|
|
91
88
|
* Main Multi-Agent Accelerator component that contains the sidebar, agent flow, and chat components.
|
|
92
89
|
* @param backendNeuroSanApiUrl Initial URL of the backend Neuro-San API. User can change this in the UI.
|
|
93
|
-
* @param
|
|
94
|
-
* @param userInfo Information about the current user, including userName and userImage.
|
|
90
|
+
* @param username Identifier to use for interactions with the backend (for personalization and tracking).
|
|
95
91
|
*/
|
|
96
|
-
export const MultiAgentAccelerator = ({
|
|
92
|
+
export const MultiAgentAccelerator = ({ defaultNeuroSanUrl, username, }) => {
|
|
97
93
|
// MUI theme
|
|
98
94
|
const theme = useTheme();
|
|
99
95
|
const enableZenMode = useSettingsStore((state) => state.settings.behavior.enableZenMode);
|
|
96
|
+
const apiKeys = useSettingsStore((state) => state.settings.apiKeys);
|
|
97
|
+
// Display option for agent/network names
|
|
98
|
+
const useNativeNames = useSettingsStore((state) => state.settings.appearance.useNativeNames);
|
|
100
99
|
// Stores whether are currently awaiting LLM response (for knowing when to show spinners)
|
|
101
100
|
const [isAwaitingLlm, setIsAwaitingLlm] = useState(false);
|
|
102
101
|
const [isEditingNetwork, setIsEditingNetwork] = useState(false);
|
|
@@ -117,13 +116,12 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
117
116
|
const [agentIconSuggestions, setAgentIconSuggestions] = useState(null);
|
|
118
117
|
const [selectedNetwork, setSelectedNetwork] = useState(null);
|
|
119
118
|
const [networkDescription, setNetworkDescription] = useState("");
|
|
120
|
-
const networkDisplayName = useMemo(() => cleanUpAgentName(removeTrailingUuid(selectedNetwork)), [selectedNetwork]);
|
|
121
|
-
const [
|
|
122
|
-
|
|
123
|
-
const [neuroSanURL, setNeuroSanURL] = useState(customURLLocalStorage?.replaceAll('"', "") || backendNeuroSanApiUrl);
|
|
119
|
+
const networkDisplayName = useMemo(() => (useNativeNames ? selectedNetwork : cleanUpAgentName(removeTrailingUuid(selectedNetwork))), [selectedNetwork, useNativeNames]);
|
|
120
|
+
const [providerKeysRequired, setProviderKeysRequired] = useState(new Set());
|
|
121
|
+
const neuroSanURL = useSettingsStore((state) => state.settings.externalServices.neuroSanUrl) ?? defaultNeuroSanUrl;
|
|
124
122
|
// Tracks how many times each agent has been involved in the conversation
|
|
125
123
|
const [agentCounts, setAgentCounts] = useState(new Map());
|
|
126
|
-
//
|
|
124
|
+
// Common function to change the selected network and reset related state
|
|
127
125
|
const changeSelectedNetwork = useCallback((next) => {
|
|
128
126
|
setSelectedNetwork(next);
|
|
129
127
|
setAgentCounts(new Map());
|
|
@@ -136,10 +134,6 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
136
134
|
const [confirmationModalOpen, setConfirmationModalOpen] = useState(false);
|
|
137
135
|
const [tourModalOpen, setTourModalOpen] = useState(false);
|
|
138
136
|
const [haveShownTourModal, setHaveShownTourModal] = useState(false);
|
|
139
|
-
const customURLCallback = useCallback((url) => {
|
|
140
|
-
setNeuroSanURL(url || backendNeuroSanApiUrl);
|
|
141
|
-
setCustomURLLocalStorage(url === "" ? null : url);
|
|
142
|
-
}, [backendNeuroSanApiUrl, setCustomURLLocalStorage]);
|
|
143
137
|
// Memoized key for agent names to trigger icon suggestion updates when the set of agents changes, not just
|
|
144
138
|
// when sorting/other operations on the agents list
|
|
145
139
|
const agentNamesKey = useMemo(() => agentsInNetwork
|
|
@@ -203,23 +197,62 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
203
197
|
const designerTempNetwork = designerNetworkName
|
|
204
198
|
? temporaryNetworks.find((n) => n.agentNetworkName === designerNetworkName)
|
|
205
199
|
: undefined;
|
|
206
|
-
|
|
200
|
+
/**
|
|
201
|
+
* Builds the API keys object to be sent as extraSlyData with each request, based on the LLM providers required
|
|
202
|
+
* by the currently selected network. Only includes keys for providers that are required.
|
|
203
|
+
*/
|
|
204
|
+
const getApiKeys = () => {
|
|
205
|
+
const llmConfig = {};
|
|
206
|
+
if (providerKeysRequired.has("OpenAI")) {
|
|
207
|
+
llmConfig["openai_api_key"] = apiKeys["OpenAI"];
|
|
208
|
+
}
|
|
209
|
+
if (providerKeysRequired.has("Anthropic")) {
|
|
210
|
+
llmConfig["anthropic_api_key"] = apiKeys["Anthropic"];
|
|
211
|
+
}
|
|
212
|
+
return { llm_config: llmConfig };
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Builds the extraSlyData object to be sent with each request, including information for Agent Network Designer
|
|
216
|
+
* and (if required) API keys for LLM providers.
|
|
217
|
+
*/
|
|
218
|
+
const buildExtraSlyData = () => {
|
|
219
|
+
if (currentTempNetwork) {
|
|
220
|
+
const result = {
|
|
221
|
+
[AGENT_NETWORK_DEFINITION_KEY]: currentTempNetwork.agentNetworkDefinition,
|
|
222
|
+
};
|
|
223
|
+
// Use agentNetworkName, not reservation_id
|
|
224
|
+
if (currentTempNetwork.agentNetworkName) {
|
|
225
|
+
result[AGENT_NETWORK_NAME_KEY] = currentTempNetwork.agentNetworkName;
|
|
226
|
+
}
|
|
227
|
+
if (currentTempNetwork.networkHocon) {
|
|
228
|
+
result[AGENT_NETWORK_HOCON] = currentTempNetwork.networkHocon;
|
|
229
|
+
}
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
232
|
+
if (designerTempNetwork) {
|
|
233
|
+
return {
|
|
234
|
+
[AGENT_NETWORK_DEFINITION_KEY]: designerTempNetwork.agentNetworkDefinition,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
return undefined;
|
|
238
|
+
};
|
|
239
|
+
// Whether any API keys are required
|
|
240
|
+
const anyApiKeysRequired = providerKeysRequired.size > 0;
|
|
241
|
+
// Build base extraSlyData
|
|
242
|
+
const baseExtraSlyData = buildExtraSlyData();
|
|
243
|
+
// Add API keys to extraSlyData if needed, merging with baseExtraSlyData if it exists
|
|
244
|
+
const extraSlyData = anyApiKeysRequired || baseExtraSlyData
|
|
207
245
|
? {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
...(currentTempNetwork.agentNetworkName
|
|
211
|
-
? { [AGENT_NETWORK_NAME_KEY]: currentTempNetwork.agentNetworkName }
|
|
212
|
-
: {}),
|
|
213
|
-
...(currentTempNetwork.networkHocon ? { [AGENT_NETWORK_HOCON]: currentTempNetwork.networkHocon } : {}),
|
|
246
|
+
...baseExtraSlyData,
|
|
247
|
+
...(anyApiKeysRequired ? getApiKeys() : {}),
|
|
214
248
|
}
|
|
215
|
-
:
|
|
216
|
-
? { [AGENT_NETWORK_DEFINITION_KEY]: designerTempNetwork.agentNetworkDefinition }
|
|
217
|
-
: undefined;
|
|
249
|
+
: undefined;
|
|
218
250
|
// Handle external stop button click - stops streaming and exits zen mode
|
|
219
251
|
const handleExternalStop = useCallback(() => {
|
|
220
252
|
chatRef.current?.handleStop();
|
|
221
253
|
resetState();
|
|
222
254
|
}, [resetState]);
|
|
255
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
223
256
|
useEffect(() => {
|
|
224
257
|
;
|
|
225
258
|
(async () => {
|
|
@@ -240,11 +273,26 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
240
273
|
const fetchAgentDetails = async () => {
|
|
241
274
|
// It is a Neuro-san agent, so get the function and connectivity info
|
|
242
275
|
try {
|
|
243
|
-
const agentFunction = await getAgentFunction(neuroSanURL, selectedNetwork,
|
|
276
|
+
const agentFunction = await getAgentFunction(neuroSanURL, selectedNetwork, username);
|
|
244
277
|
setNetworkDescription(agentFunction?.function?.description || "");
|
|
278
|
+
const schema = agentFunction?.function?.sly_data_schema;
|
|
279
|
+
const schemaProperties = isRecord(schema) ? schema["properties"] : undefined;
|
|
280
|
+
const llmConfig = isRecord(schemaProperties) ? schemaProperties["llm_config"] : undefined;
|
|
281
|
+
const llmConfigRequired = isRecord(llmConfig) ? llmConfig["required"] : undefined;
|
|
282
|
+
setProviderKeysRequired(new Set((Array.isArray(llmConfigRequired) ? llmConfigRequired : []).flatMap((key) => {
|
|
283
|
+
if (key === "openai_api_key") {
|
|
284
|
+
return ["OpenAI"];
|
|
285
|
+
}
|
|
286
|
+
if (key === "anthropic_api_key") {
|
|
287
|
+
return ["Anthropic"];
|
|
288
|
+
}
|
|
289
|
+
console.warn(`Unknown API key requirement "${key}" for network ${selectedNetwork}. Skipping.`);
|
|
290
|
+
// Will get dropped by flatMap
|
|
291
|
+
return [];
|
|
292
|
+
})));
|
|
245
293
|
}
|
|
246
|
-
catch {
|
|
247
|
-
|
|
294
|
+
catch (e) {
|
|
295
|
+
console.warn(`Unable to get agent details for network ${selectedNetwork}:`, e);
|
|
248
296
|
}
|
|
249
297
|
};
|
|
250
298
|
// Clear out existing
|
|
@@ -252,7 +300,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
252
300
|
if (selectedNetwork && !isLegacyAgentType(selectedNetwork)) {
|
|
253
301
|
void fetchAgentDetails();
|
|
254
302
|
}
|
|
255
|
-
}, [neuroSanURL, selectedNetwork,
|
|
303
|
+
}, [neuroSanURL, selectedNetwork, username]);
|
|
256
304
|
useEffect(() => {
|
|
257
305
|
;
|
|
258
306
|
(async () => {
|
|
@@ -273,7 +321,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
273
321
|
(async () => {
|
|
274
322
|
if (selectedNetwork) {
|
|
275
323
|
try {
|
|
276
|
-
const connectivity = await getConnectivity(neuroSanURL, selectedNetwork,
|
|
324
|
+
const connectivity = await getConnectivity(neuroSanURL, selectedNetwork, username);
|
|
277
325
|
const agentsInNetworkSorted = [...connectivity.connectivity_info].sort((a, b) => a?.origin.localeCompare(b?.origin));
|
|
278
326
|
setAgentsInNetwork(agentsInNetworkSorted);
|
|
279
327
|
const sampleQueriesTmp = connectivity?.metadata?.["sample_queries"];
|
|
@@ -296,7 +344,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
296
344
|
setAgentsInNetwork([]);
|
|
297
345
|
}
|
|
298
346
|
})();
|
|
299
|
-
}, [networkDisplayName, neuroSanURL, selectedNetwork,
|
|
347
|
+
}, [networkDisplayName, neuroSanURL, selectedNetwork, username]);
|
|
300
348
|
useEffect(() => {
|
|
301
349
|
;
|
|
302
350
|
(async () => {
|
|
@@ -419,7 +467,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
419
467
|
const onSaveAgent = useCallback(async (agentName, updated, agentNetworkName, signal) => {
|
|
420
468
|
try {
|
|
421
469
|
let newNetworks = [];
|
|
422
|
-
await sendNetworkDesignerUpdate(neuroSanURL, signal, agentName, updated, agentNetworkName,
|
|
470
|
+
await sendNetworkDesignerUpdate(neuroSanURL, signal, agentName, updated, agentNetworkName, username, (chunk) => {
|
|
423
471
|
newNetworks = collectNetworksFromChunk(chunk, updated, newNetworks);
|
|
424
472
|
});
|
|
425
473
|
if (newNetworks.length === 0) {
|
|
@@ -443,7 +491,7 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
443
491
|
catch (e) {
|
|
444
492
|
notifySaveError(agentName, e);
|
|
445
493
|
}
|
|
446
|
-
}, [neuroSanURL,
|
|
494
|
+
}, [neuroSanURL, username, selectedNetwork]);
|
|
447
495
|
const onStreamingStarted = useCallback(() => {
|
|
448
496
|
// Reset agent counts
|
|
449
497
|
setAgentCounts(new Map());
|
|
@@ -506,12 +554,15 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
506
554
|
setTourRequested(false);
|
|
507
555
|
}
|
|
508
556
|
}, [tourRequested, selectedNetwork, agentsInNetwork, networks, controls, setTourStatus]);
|
|
557
|
+
const getMissingApiKeys = () => {
|
|
558
|
+
return providerKeysRequired.size > 0 ? [...providerKeysRequired].filter((provider) => !apiKeys?.[provider]) : [];
|
|
559
|
+
};
|
|
509
560
|
const getLeftPanel = () => {
|
|
510
561
|
return (_jsx(Slide, { id: "multi-agent-accelerator-grid-sidebar-slide", in: !enableZenMode || !isAwaitingLlm, direction: "right", timeout: GROW_ANIMATION_TIME_MS, onExited: () => {
|
|
511
562
|
setIsStreaming(true);
|
|
512
563
|
}, children: _jsx(Grid, { id: "multi-agent-accelerator-grid-sidebar", size: enableZenMode && isStreaming ? 0 : 3.25, sx: {
|
|
513
564
|
height: "100%",
|
|
514
|
-
}, children: _jsx(Sidebar, {
|
|
565
|
+
}, children: _jsx(Sidebar, { id: "multi-agent-accelerator-sidebar", isAwaitingLlm: isAwaitingLlm, networkIconSuggestions: networkIconSuggestions, networks: networks, neuroSanServerURL: neuroSanURL, newlyAddedTemporaryNetworks: newlyAddedTemporaryNetworks, onDeleteNetwork: handleDeleteNetwork, onEditNetwork: handleEditNetwork, setSelectedNetwork: (newNetwork) => changeSelectedNetwork(newNetwork), temporaryNetworks: temporaryNetworks }) }) }));
|
|
515
566
|
};
|
|
516
567
|
const getCenterPanel = () => {
|
|
517
568
|
return (_jsx(Grid, { id: "multi-agent-accelerator-grid-agent-flow", size: enableZenMode && isStreaming ? 18 : 8.25, sx: {
|
|
@@ -524,26 +575,30 @@ export const MultiAgentAccelerator = ({ backendNeuroSanApiUrl, userInfo, }) => {
|
|
|
524
575
|
height: "100%",
|
|
525
576
|
maxWidth: 1000,
|
|
526
577
|
margin: "0 auto",
|
|
527
|
-
}, children: _jsx(AgentFlow, { agentCounts: agentCounts, agentsInNetwork: agentsInNetwork, agentIconSuggestions: agentIconSuggestions, id: "multi-agent-accelerator-agent-flow", currentConversations: currentConversations, currentUser:
|
|
578
|
+
}, 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") }) }) }));
|
|
528
579
|
};
|
|
529
580
|
const getRightPanel = () => {
|
|
530
581
|
return (_jsx(Slide, { id: "multi-agent-accelerator-grid-agent-chat-common-slide", in: !enableZenMode || !isAwaitingLlm, direction: "left", timeout: GROW_ANIMATION_TIME_MS, onExited: () => {
|
|
531
582
|
setIsStreaming(true);
|
|
532
583
|
}, children: _jsx(Grid, { id: "multi-agent-accelerator-grid-agent-chat-common", size: enableZenMode && isStreaming ? 0 : 6.5, sx: {
|
|
533
584
|
height: "100%",
|
|
534
|
-
}, children: _jsx(ChatCommon, {
|
|
535
|
-
[AGENT_NETWORK_DESIGNER_ID]: "Let's build a network together!",
|
|
536
|
-
}, agentPlaceholders: {
|
|
585
|
+
}, children: _jsx(ChatCommon, { agentPlaceholders: {
|
|
537
586
|
[AGENT_NETWORK_DESIGNER_ID]: "Describe in plain language the network you would like to build.",
|
|
538
|
-
}, currentUser:
|
|
587
|
+
}, currentUser: username, customAgentGreetings: {
|
|
588
|
+
[AGENT_NETWORK_DESIGNER_ID]: "Let's build a network together!",
|
|
589
|
+
}, 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, setSelectedNetwork: changeSelectedNetwork }, selectedNetwork ?? "no-network") }) }));
|
|
539
590
|
};
|
|
540
591
|
const getStopButton = () => {
|
|
541
592
|
return (_jsx(_Fragment, { children: isAwaitingLlm && enableZenMode && (_jsx(Box, { id: "stop-button-container", sx: {
|
|
542
593
|
position: "absolute",
|
|
543
594
|
bottom: "1rem",
|
|
544
595
|
right: "1rem",
|
|
545
|
-
zIndex:
|
|
546
|
-
}, children: _jsx(
|
|
596
|
+
zIndex: getZIndex(2, theme),
|
|
597
|
+
}, children: _jsx(Tooltip, { title: "Stop response (Esc)", children: _jsx(LlmChatButton, { "aria-label": "Stop", id: "stop-output-button", onClick: handleExternalStop, sx: {
|
|
598
|
+
"&:hover": {
|
|
599
|
+
backgroundColor: "error.main",
|
|
600
|
+
},
|
|
601
|
+
}, children: _jsx(StopCircle, { fontSize: "large", id: "stop-button-icon" }) }) }) })) }));
|
|
547
602
|
};
|
|
548
603
|
const getDeleteNetworkConfirmationModal = () => confirmationModalOpen ? (_jsx(ConfirmationModal, { id: "delete-network-confirmation-modal", content: `The network "${cleanUpAgentName(removeTrailingUuid(networkToBeDeleted))}" will be deleted. ` +
|
|
549
604
|
"This action cannot be undone. Are you sure you want to proceed?", handleCancel: () => {
|
|
@@ -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
|
|
@@ -9,14 +9,13 @@ import Edit from "@mui/icons-material/Edit";
|
|
|
9
9
|
import Box from "@mui/material/Box";
|
|
10
10
|
import Chip from "@mui/material/Chip";
|
|
11
11
|
import IconButton from "@mui/material/IconButton";
|
|
12
|
-
import { useTheme } from "@mui/material/styles";
|
|
13
12
|
import Tooltip from "@mui/material/Tooltip";
|
|
13
|
+
import { useTreeItemModel } from "@mui/x-tree-view/hooks";
|
|
14
14
|
import { TreeItemContent, TreeItemGroupTransition, TreeItemLabel, TreeItemRoot, } from "@mui/x-tree-view/TreeItem";
|
|
15
15
|
import { TreeItemProvider } from "@mui/x-tree-view/TreeItemProvider";
|
|
16
16
|
import { useTreeItem } from "@mui/x-tree-view/useTreeItem";
|
|
17
17
|
import { useRef } from "react";
|
|
18
18
|
import { downloadFile, toSafeFilename } from "../../../utils/File.js";
|
|
19
|
-
import { cleanUpAgentName } from "../../AgentChat/Common/Utils.js";
|
|
20
19
|
// Palette of colors we can use for tags
|
|
21
20
|
const TAG_COLORS = [
|
|
22
21
|
"--bs-accent2-light",
|
|
@@ -44,21 +43,15 @@ const isTemporaryNetworkExpired = (expirationDate) => {
|
|
|
44
43
|
* @param props - see AgentNetworkNode interface
|
|
45
44
|
* @returns JSX.Element containing the custom tree item
|
|
46
45
|
*/
|
|
47
|
-
export const AgentNetworkTreeItem = ({ children, disabled, itemId, label,
|
|
48
|
-
const
|
|
46
|
+
export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, onDeleteNetwork, onEditNetwork, }) => {
|
|
47
|
+
const item = useTreeItemModel(itemId);
|
|
49
48
|
// We know all labels are strings because we set them that way in the tree view items
|
|
50
49
|
const labelString = label;
|
|
51
|
-
const displayLabel = nodeIndex.get(itemId)?.displayName || cleanUpAgentName(labelString);
|
|
52
50
|
const { getContextProviderProps, getRootProps, getContentProps, getLabelProps, getGroupTransitionProps } = useTreeItem({ itemId, children, label, disabled });
|
|
53
51
|
const rootRef = useRef(null);
|
|
54
52
|
const isParent = Array.isArray(children) && children.length > 0;
|
|
55
53
|
const isChild = !isParent;
|
|
56
|
-
const
|
|
57
|
-
// Only child items (the actual networks, not the containing folders) have tags. Retrieve tags from the
|
|
58
|
-
// networkFolders data structure passed in as a prop. This could in theory be a custom property for the
|
|
59
|
-
// RichTreeView item, but that isn't well-supported at this time.
|
|
60
|
-
// Discussion: https://stackoverflow.com/questions/69481071/material-ui-how-to-pass-custom-props-to-a-custom-treeitem
|
|
61
|
-
const tags = isChild ? agentNode?.tags || [] : [];
|
|
54
|
+
const tags = item.tags ?? [];
|
|
62
55
|
// Assign colors to tags as needed and store in tagsToColors map
|
|
63
56
|
for (const tag of tags) {
|
|
64
57
|
if (!tagsToColors.has(tag)) {
|
|
@@ -67,18 +60,33 @@ export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, networ
|
|
|
67
60
|
}
|
|
68
61
|
}
|
|
69
62
|
// Determine if expired (temporary networks only)
|
|
70
|
-
const expirationTime =
|
|
63
|
+
const expirationTime = item?.temporaryNetworkExpirationTime;
|
|
71
64
|
const isTemporaryNetwork = Boolean(expirationTime);
|
|
72
65
|
const isExpired = isChild && isTemporaryNetwork && isTemporaryNetworkExpired(expirationTime);
|
|
73
|
-
const networkHocon =
|
|
74
|
-
const iconNameSuggestion =
|
|
75
|
-
let muiIconElement
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
66
|
+
const networkHocon = item?.temporaryNetworkHocon ?? null;
|
|
67
|
+
const iconNameSuggestion = item.iconSuggestion;
|
|
68
|
+
let muiIconElement;
|
|
69
|
+
// If the item is a child (i.e., a network), we want to render an icon next to it.
|
|
70
|
+
if (isChild) {
|
|
71
|
+
if (iconNameSuggestion) {
|
|
72
|
+
if (MuiIcons[iconNameSuggestion]) {
|
|
73
|
+
// If the icon name suggestion is valid, use it to render the icon
|
|
74
|
+
const IconComponent = MuiIcons[iconNameSuggestion];
|
|
75
|
+
muiIconElement = _jsx(IconComponent, { sx: { fontSize: "1rem" } });
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// If the icon name suggestion is not valid, use a default icon
|
|
79
|
+
muiIconElement = _jsx(MuiIcons.Hub, { sx: { fontSize: "1rem" } });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// If no icon name suggestion is provided, use a default icon
|
|
84
|
+
muiIconElement = _jsx(MuiIcons.Hub, { sx: { fontSize: "1rem" } });
|
|
85
|
+
}
|
|
79
86
|
}
|
|
80
|
-
else
|
|
81
|
-
|
|
87
|
+
else {
|
|
88
|
+
// Use folder icon for parent items (i.e., folders)
|
|
89
|
+
muiIconElement = _jsx(MuiIcons.Folder, { sx: { fontSize: "1rem" } });
|
|
82
90
|
}
|
|
83
91
|
return (_jsx(TreeItemProvider, { ...getContextProviderProps(), children: _jsxs(TreeItemRoot, { ...getRootProps(), ref: rootRef, "data-itemid": itemId, children: [_jsx(TreeItemContent, { ...getContentProps(), sx: {
|
|
84
92
|
cursor: isExpired ? "not-allowed" : "pointer",
|
|
@@ -92,16 +100,13 @@ export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, networ
|
|
|
92
100
|
"&:hover": {
|
|
93
101
|
textDecoration: "underline",
|
|
94
102
|
},
|
|
95
|
-
}, children:
|
|
103
|
+
}, children: item.displayName })] }) }), isChild && tags.length > 0 ? (_jsx(Tooltip, { title: [...tags]
|
|
96
104
|
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
|
|
97
105
|
.map((tag) => (_jsx(Chip, { label: tag, style: {
|
|
98
106
|
margin: "0.25rem",
|
|
99
107
|
backgroundColor: `var(${tagsToColors.get(tag) || TAG_COLORS[0]})`,
|
|
100
108
|
} }, tag))), placement: "right", arrow: true, children: _jsx(BookmarkIcon, { sx: { fontSize: "0.75rem", color: "var(--bs-accent1-medium)" } }) })) : null] }), isChild && isTemporaryNetwork && (_jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: "0.25rem", marginLeft: "auto" }, children: [networkHocon && (_jsx(Tooltip, { title: isExpired ? "Expired" : "Download network definition", children: _jsx("span", { children: _jsx(IconButton, { onClick: (e) => {
|
|
101
109
|
e.stopPropagation();
|
|
102
|
-
if (isExpired) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
110
|
const fileName = `${toSafeFilename(labelString)}.hocon`;
|
|
106
111
|
downloadFile(networkHocon, fileName);
|
|
107
112
|
}, disabled: isExpired, "aria-label": "Download network definition", size: "small", sx: {
|
|
@@ -128,7 +133,7 @@ export const AgentNetworkTreeItem = ({ children, disabled, itemId, label, networ
|
|
|
128
133
|
onDeleteNetwork?.(itemId, isExpired);
|
|
129
134
|
}, sx: {
|
|
130
135
|
color: "var(--bs-secondary)",
|
|
131
|
-
"&:hover": { color: theme.palette.warning.main },
|
|
136
|
+
"&:hover": { color: (theme) => theme.palette.warning.main },
|
|
132
137
|
"&.Mui-disabled": {
|
|
133
138
|
color: "var(--bs-secondary)",
|
|
134
139
|
opacity: 0.3,
|
|
@@ -4,16 +4,15 @@ import { AgentInfo } from "../../../generated/neuro-san/NeuroSanClient.js";
|
|
|
4
4
|
import { TemporaryNetwork } from "../../../state/TemporaryNetworks.js";
|
|
5
5
|
export declare const SPARKLE_HIGHLIGHT_CLASS = "sparkle-highlight";
|
|
6
6
|
export interface SidebarProps {
|
|
7
|
-
readonly customURLCallback: (url: string) => void;
|
|
8
|
-
readonly customURLLocalStorage?: string;
|
|
9
7
|
readonly id: string;
|
|
10
8
|
readonly isAwaitingLlm: boolean;
|
|
11
9
|
readonly networkIconSuggestions?: NetworkIconSuggestions;
|
|
12
10
|
readonly networks: readonly AgentInfo[];
|
|
13
|
-
readonly
|
|
11
|
+
readonly neuroSanServerURL: string;
|
|
12
|
+
readonly newlyAddedTemporaryNetworks?: Set<string>;
|
|
14
13
|
readonly onDeleteNetwork?: (network: string, isExpired: boolean) => void;
|
|
14
|
+
readonly onEditNetwork?: (network: string) => void;
|
|
15
15
|
readonly setSelectedNetwork: (network: string) => void;
|
|
16
16
|
readonly temporaryNetworks?: readonly TemporaryNetwork[];
|
|
17
|
-
readonly newlyAddedTemporaryNetworks?: Set<string>;
|
|
18
17
|
}
|
|
19
18
|
export declare const Sidebar: FC<SidebarProps>;
|