@cognizant-ai-lab/ui-common 1.7.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 +4 -1
- package/dist/components/AgentChat/ChatCommon/ChatCommon.js +74 -47
- 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/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 +28 -32
- 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.js +7 -8
- package/dist/components/Settings/InfoTip.d.ts +8 -0
- package/dist/components/Settings/InfoTip.js +14 -0
- package/dist/components/Settings/SettingsDialog.js +355 -181
- 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/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 +17 -3
- package/dist/state/Settings.js +23 -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 -47
- 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
package/dist/Theme/Palettes.d.ts
CHANGED
|
@@ -7,12 +7,3 @@ export declare const PALETTES: {
|
|
|
7
7
|
coldToHot: string[];
|
|
8
8
|
visionImpaired: string[];
|
|
9
9
|
};
|
|
10
|
-
export type PaletteKey = keyof typeof PALETTES | "brand";
|
|
11
|
-
/**
|
|
12
|
-
* Custom hook to get the current color palette based on user settings.
|
|
13
|
-
* If the user has selected custom branding, it will return the palette for that.
|
|
14
|
-
* Otherwise, it will return one of the predefined palettes from the PALETTES object based on the user's selection.
|
|
15
|
-
*
|
|
16
|
-
* @returns An array of color hex codes representing the current color palette.
|
|
17
|
-
*/
|
|
18
|
-
export declare const usePalette: () => string[];
|
package/dist/Theme/Palettes.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// Palettes for progressive coloring of nodes based on depth or heatmap value
|
|
2
|
-
import { useSettingsStore } from "../state/Settings.js";
|
|
3
2
|
export const PALETTES = {
|
|
4
3
|
blue: [
|
|
5
4
|
"#f7fbff",
|
|
@@ -75,20 +74,3 @@ export const PALETTES = {
|
|
|
75
74
|
"#b6dbff",
|
|
76
75
|
],
|
|
77
76
|
};
|
|
78
|
-
/**
|
|
79
|
-
* Custom hook to get the current color palette based on user settings.
|
|
80
|
-
* If the user has selected custom branding, it will return the palette for that.
|
|
81
|
-
* Otherwise, it will return one of the predefined palettes from the PALETTES object based on the user's selection.
|
|
82
|
-
*
|
|
83
|
-
* @returns An array of color hex codes representing the current color palette.
|
|
84
|
-
*/
|
|
85
|
-
export const usePalette = () => {
|
|
86
|
-
const brandPalette = useSettingsStore((state) => state.settings.branding.rangePalette);
|
|
87
|
-
const paletteKey = useSettingsStore((state) => state.settings.appearance.rangePalette);
|
|
88
|
-
if (paletteKey === "brand" && brandPalette) {
|
|
89
|
-
return brandPalette;
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
return PALETTES[paletteKey];
|
|
93
|
-
}
|
|
94
|
-
};
|
|
@@ -22,6 +22,10 @@ export interface ChatCommonProps {
|
|
|
22
22
|
* The network to send the request to.
|
|
23
23
|
*/
|
|
24
24
|
readonly selectedNetwork: string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Setter for changing the selected network.
|
|
27
|
+
*/
|
|
28
|
+
readonly setSelectedNetwork?: (network: string | null) => void;
|
|
25
29
|
/**
|
|
26
30
|
* Special endpoint for legacy agents since they do not have a single unified endpoint like Neuro-san agents.
|
|
27
31
|
*/
|
|
@@ -100,7 +104,6 @@ export type ChatCommonHandle = {
|
|
|
100
104
|
handleStop: () => void;
|
|
101
105
|
handleClearChat: () => void;
|
|
102
106
|
};
|
|
103
|
-
export declare const MAX_TURNS = 50;
|
|
104
107
|
/**
|
|
105
108
|
* Common chat component for agent chat. This component is used by all agent chat components to provide a consistent
|
|
106
109
|
* experience for users when chatting with agents. It handles user input as well as displaying and nicely formatting
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
/*
|
|
3
3
|
Copyright 2025 Cognizant Technology Solutions Corp, www.cognizant.com.
|
|
4
4
|
|
|
@@ -18,6 +18,7 @@ limitations under the License.
|
|
|
18
18
|
* See main function description.
|
|
19
19
|
*/
|
|
20
20
|
import { AIMessage, HumanMessage } from "@langchain/core/messages";
|
|
21
|
+
import AddBoxRounded from "@mui/icons-material/AddBoxRounded";
|
|
21
22
|
import ClearIcon from "@mui/icons-material/Clear";
|
|
22
23
|
import CloseIcon from "@mui/icons-material/Close";
|
|
23
24
|
import TuneIcon from "@mui/icons-material/Tune";
|
|
@@ -37,6 +38,7 @@ import { isEmpty } from "lodash-es";
|
|
|
37
38
|
import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from "react";
|
|
38
39
|
import { v4 as uuid } from "uuid";
|
|
39
40
|
import { ChatHistory } from "./ChatHistory.js";
|
|
41
|
+
import { MAX_TURNS } from "./Const.js";
|
|
40
42
|
import { ControlButtons } from "./ControlButtons.js";
|
|
41
43
|
import { Conversation } from "./Conversation.js";
|
|
42
44
|
import { MessageRole } from "./ConversationTurn.js";
|
|
@@ -47,11 +49,16 @@ import { sendChatQuery } from "../../../controller/agent/Agent.js";
|
|
|
47
49
|
import { sendLlmRequest, StreamingUnit } from "../../../controller/llm/LlmChat.js";
|
|
48
50
|
import { ChatMessageType } from "../../../generated/neuro-san/NeuroSanClient.js";
|
|
49
51
|
import { useAgentChatHistoryStore } from "../../../state/ChatHistory.js";
|
|
52
|
+
import { useSettingsStore } from "../../../state/Settings.js";
|
|
50
53
|
import { hasOnlyWhitespace } from "../../../utils/text.js";
|
|
54
|
+
import { getZIndex } from "../../../utils/zIndexLayers.js";
|
|
55
|
+
import { AGENT_NETWORK_DESIGNER_ID } from "../../MultiAgentAccelerator/const.js";
|
|
51
56
|
import { givesFinalAnswer, isLegacyAgentType } from "../Common/Types.js";
|
|
52
57
|
import { chatMessageFromChunk, checkError, cleanUpAgentName, removeTrailingUuid } from "../Common/Utils.js";
|
|
53
58
|
import { MicrophoneButton } from "../VoiceChat/MicrophoneButton.js";
|
|
54
59
|
import { cleanupAndStopSpeechRecognition, setupSpeechRecognition } from "../VoiceChat/VoiceChat.js";
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region Constants
|
|
55
62
|
// Define fancy EMPTY constant to avoid linter error about using object literals as default props
|
|
56
63
|
const EMPTY = {};
|
|
57
64
|
// How many times to retry the entire agent interaction process. Some networks have a well-defined success condition.
|
|
@@ -63,15 +70,14 @@ const MAX_AGENT_RETRIES = 3;
|
|
|
63
70
|
* @returns The final answer from the agent, if it exists or undefined if it doesn't
|
|
64
71
|
*/
|
|
65
72
|
const extractFinalAnswer = (response) => /Final Answer: (?<finalAnswerText>.*)/su.exec(response)?.groups?.["finalAnswerText"];
|
|
66
|
-
|
|
67
|
-
export const MAX_TURNS = 50;
|
|
73
|
+
//#endregion
|
|
68
74
|
/**
|
|
69
75
|
* Common chat component for agent chat. This component is used by all agent chat components to provide a consistent
|
|
70
76
|
* experience for users when chatting with agents. It handles user input as well as displaying and nicely formatting
|
|
71
77
|
* agent responses. Customization for inputs and outputs is provided via event handlers-like props.
|
|
72
78
|
*/
|
|
73
79
|
export const ChatCommon = ({ ref, ...props }) => {
|
|
74
|
-
const {
|
|
80
|
+
const { agentPlaceholders = EMPTY, backgroundColor, currentUser, customAgentGreetings = EMPTY, extraParams, extraSlyData, id, isAwaitingLlm, legacyAgentEndpoint, missingApiKeys = [], networkDescription, neuroSanURL, onChunkReceived, onClose, onSend, onStreamingComplete, onStreamingStarted, sampleQueries, selectedNetwork, setIsAwaitingLlm, setPreviousResponse, setSelectedNetwork, title, } = props;
|
|
75
81
|
// MUI theme
|
|
76
82
|
const theme = useTheme();
|
|
77
83
|
// User LLM chat input
|
|
@@ -100,6 +106,8 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
100
106
|
// (see store implementation for details)
|
|
101
107
|
const storedChatHistory = useAgentChatHistoryStore((state) => selectedNetwork ? state?.history?.[selectedNetwork] : undefined);
|
|
102
108
|
const agentChatHistory = useMemo(() => storedChatHistory ?? { chatHistory: [], chatContext: null, slyData: {} }, [storedChatHistory]);
|
|
109
|
+
// Display option for agent/network names
|
|
110
|
+
const useNativeNames = useSettingsStore((state) => state.settings.appearance.useNativeNames);
|
|
103
111
|
// Access store for context items
|
|
104
112
|
const updateChatContext = useAgentChatHistoryStore((state) => state.updateChatContext);
|
|
105
113
|
const updateChatHistory = useAgentChatHistoryStore((state) => state.updateChatHistory);
|
|
@@ -134,7 +142,7 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
134
142
|
};
|
|
135
143
|
// Keeps track of whether the agent completed its task
|
|
136
144
|
const succeeded = useRef(false);
|
|
137
|
-
const
|
|
145
|
+
const networkDisplayName = useMemo(() => (useNativeNames ? selectedNetwork : cleanUpAgentName(removeTrailingUuid(selectedNetwork))), [selectedNetwork, useNativeNames]);
|
|
138
146
|
useEffect(() => {
|
|
139
147
|
// Set up speech recognition
|
|
140
148
|
const handlers = setupSpeechRecognition(setChatInput, setVoiceInputState, speechRecognitionRef);
|
|
@@ -169,7 +177,11 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
169
177
|
const legacyTurnIdRef = useRef(null);
|
|
170
178
|
const handleLegacyAgentChunk = useCallback((chunk) => {
|
|
171
179
|
currentResponse.current += chunk;
|
|
172
|
-
if (
|
|
180
|
+
if (legacyTurnIdRef.current) {
|
|
181
|
+
// We already have a turn for this response, so just update the text of that turn.
|
|
182
|
+
setTurns((prev) => prev.map((t) => (t.id === legacyTurnIdRef.current ? { ...t, text: currentResponse.current } : t)));
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
173
185
|
// We don't yet have a turn for this response, so create one. On subsequent chunks, we'll just
|
|
174
186
|
// update the text of this turn.
|
|
175
187
|
legacyTurnIdRef.current = uuid();
|
|
@@ -180,10 +192,6 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
180
192
|
text: currentResponse.current,
|
|
181
193
|
});
|
|
182
194
|
}
|
|
183
|
-
else {
|
|
184
|
-
// We already have a turn for this response, so just update the text of that turn.
|
|
185
|
-
setTurns((prev) => prev.map((t) => (t.id === legacyTurnIdRef.current ? { ...t, text: currentResponse.current } : t)));
|
|
186
|
-
}
|
|
187
195
|
}, [addTurn]);
|
|
188
196
|
const handleNeuroSanAgentChunk = useCallback((chunk) => {
|
|
189
197
|
// For Neuro-san agents, we expect a ChatMessage structure in the chunk.
|
|
@@ -219,9 +227,7 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
219
227
|
// This is the normal happy path for an incoming message.
|
|
220
228
|
// The backend sometimes sends messages with no text content, and we don't want to display those to the
|
|
221
229
|
// user. Agent name is the last tool in the origin array. If it's not there, use a default name.
|
|
222
|
-
const agentName = chatMessage.origin?.
|
|
223
|
-
? cleanUpAgentName(chatMessage.origin[chatMessage.origin.length - 1].tool)
|
|
224
|
-
: "Agent";
|
|
230
|
+
const agentName = chatMessage.origin?.at(-1)?.tool ?? "agent";
|
|
225
231
|
addTurn({
|
|
226
232
|
agentName,
|
|
227
233
|
id: uuid(),
|
|
@@ -283,8 +289,8 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
283
289
|
else {
|
|
284
290
|
// It's a Neuro-san agent.
|
|
285
291
|
// Some coded tools (data generator...) expect the username provided in slyData.
|
|
286
|
-
const
|
|
287
|
-
await sendChatQuery(neuroSanURL, controller?.current.signal, query, selectedNetwork, handleChunk, agentChatHistory.chatContext,
|
|
292
|
+
const slyDataWithUsername = { ...agentChatHistory?.slyData, ...extraSlyData, login: currentUser };
|
|
293
|
+
await sendChatQuery(neuroSanURL, controller?.current.signal, query, selectedNetwork, handleChunk, agentChatHistory.chatContext, slyDataWithUsername, currentUser, StreamingUnit.Line);
|
|
288
294
|
}
|
|
289
295
|
}
|
|
290
296
|
catch (error) {
|
|
@@ -477,7 +483,7 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
477
483
|
const shouldEnableRegenerateButton = previousUserQuery && !isAwaitingLlm;
|
|
478
484
|
// Enable Clear Chat button if not awaiting response and there is chat output to clear
|
|
479
485
|
const enableClearChatButton = !isAwaitingLlm && (turns.length > 0 || agentChatHistory?.chatHistory?.length > 0);
|
|
480
|
-
const getPlaceholder = () => selectedNetwork ? agentPlaceholders[selectedNetwork] || `Chat with ${
|
|
486
|
+
const getPlaceholder = () => selectedNetwork ? agentPlaceholders[selectedNetwork] || `Chat with ${networkDisplayName}` : null;
|
|
481
487
|
const handleClearChat = useCallback(() => {
|
|
482
488
|
setTurns([]);
|
|
483
489
|
resetHistory(selectedNetwork);
|
|
@@ -495,7 +501,7 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
495
501
|
left: 0,
|
|
496
502
|
right: 0,
|
|
497
503
|
bottom: 0,
|
|
498
|
-
zIndex: theme
|
|
504
|
+
zIndex: getZIndex(2, theme),
|
|
499
505
|
cursor: "not-allowed",
|
|
500
506
|
// Capture all pointer events to prevent interaction with the chat when no agent is selected
|
|
501
507
|
pointerEvents: "all",
|
|
@@ -516,14 +522,17 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
516
522
|
paddingTop: "0.25rem",
|
|
517
523
|
paddingBottom: "0.25rem",
|
|
518
524
|
}, children: [_jsx(Typography, { id: `llm-chat-title-${id}-text`, sx: { fontSize: "0.9rem" }, children: title }), onClose && (_jsx(IconButton, { "data-testid": `close-button-${id}`, id: `close-button-${id}`, onClick: onClose, children: _jsx(CloseIcon, { id: `close-icon-${id}` }) }))] }));
|
|
519
|
-
const getOptionsMenuButton = () => (_jsx(Box, { sx: {
|
|
525
|
+
const getOptionsMenuButton = () => (_jsx(Box, { id: `${id}-options-menu-button-container`, sx: {
|
|
526
|
+
backgroundColor: theme.palette.background.paper,
|
|
527
|
+
borderRadius: "var(--bs-border-radius)",
|
|
520
528
|
position: "absolute",
|
|
521
|
-
|
|
522
|
-
|
|
529
|
+
right: theme.spacing(2.5),
|
|
530
|
+
top: theme.spacing(1),
|
|
531
|
+
zIndex: getZIndex(2, theme),
|
|
523
532
|
}, children: _jsx(IconButton, { onClick: (e) => {
|
|
524
533
|
setOptionsMenuAnchorEl(e.currentTarget);
|
|
525
534
|
setOptionsMenuOpen(true);
|
|
526
|
-
}, children: _jsx(TuneIcon, {
|
|
535
|
+
}, children: _jsx(TuneIcon, { fontSize: "small" }) }) }));
|
|
527
536
|
const agentGreeting = customAgentGreetings[selectedNetwork] ?? "Hi, how can I help?";
|
|
528
537
|
const handleOptionsMenuClose = () => {
|
|
529
538
|
setOptionsMenuAnchorEl(null);
|
|
@@ -546,7 +555,22 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
546
555
|
},
|
|
547
556
|
},
|
|
548
557
|
}, children: [_jsxs(MenuItem, { onClick: handleToggleAutoScroll, children: [_jsx(ListItemIcon, { children: _jsx(Checkbox, { checked: autoScrollEnabled, tabIndex: -1, sx: { pointerEvents: "none" } }) }), _jsx(ListItemText, { primary: "Auto-scroll output" })] }), _jsxs(MenuItem, { onClick: handleToggleWrapOutput, children: [_jsx(ListItemIcon, { children: _jsx(Checkbox, { checked: shouldWrapOutput, tabIndex: -1, sx: { pointerEvents: "none" } }) }), _jsx(ListItemText, { primary: "Wrap output" })] })] }));
|
|
549
|
-
const
|
|
558
|
+
const getNetworkIntro = () => (_jsxs(Box, { sx: { marginBottom: "0.5rem", marginTop: "1rem" }, children: [_jsxs(Typography, { component: "span", sx: { fontWeight: 700 }, variant: "inherit", children: [networkDisplayName, networkDescription && ":"] }), networkDescription && (_jsxs(Typography, { component: "span", sx: { ml: 0.5 }, variant: "inherit", children: [" ", networkDescription] }))] }));
|
|
559
|
+
const getChatHistory = () => (_jsx(_Fragment, { children: agentChatHistory?.chatHistory?.length > 0 && (_jsx(Box, { sx: { my: "0.5rem" }, children: _jsx(ChatHistory, { id: id, messages: agentChatHistory.chatHistory }) })) }));
|
|
560
|
+
const getAgentGreeting = () => _jsx(Box, { sx: { marginBottom: "0.5rem", marginTop: "1rem" }, children: agentGreeting });
|
|
561
|
+
const getControlButtons = () => (_jsx(Box, { sx: {
|
|
562
|
+
bottom: theme.spacing(3),
|
|
563
|
+
right: theme.spacing(3),
|
|
564
|
+
position: "absolute",
|
|
565
|
+
zIndex: getZIndex(2, theme),
|
|
566
|
+
}, children: _jsx(ControlButtons, { enableClearChatButton: enableClearChatButton, handleClearChat: handleClearChat, handleSend: handleSend, handleStop: handleStop, isAwaitingLlm: isAwaitingLlm, previousUserQuery: previousUserQuery, shouldEnableRegenerateButton: shouldEnableRegenerateButton }) }));
|
|
567
|
+
const getWorkingSpinner = () => (_jsx(_Fragment, { children: isAwaitingLlm && (_jsxs(Box, { id: "awaitingOutputContainer", sx: { display: "flex", alignItems: "center", fontSize: "smaller" }, children: [_jsx("span", { id: "working-span", style: { marginRight: "1rem" }, children: "Working..." }), _jsx(CircularProgress, { id: "awaitingOutputSpinner", sx: {
|
|
568
|
+
color: "var(--bs-primary)",
|
|
569
|
+
}, size: "1rem" })] })) }));
|
|
570
|
+
const getThinking = () => (_jsx(_Fragment, { children: !isAwaitingLlm && turns.length > 0 && (
|
|
571
|
+
// Only show thinking once streaming is complete
|
|
572
|
+
_jsx(Thinking, { id: id, turns: turns, useNativeNames: useNativeNames })) }));
|
|
573
|
+
const getResponseBox = () => (_jsx(Box, { id: "llm-response-div", sx: {
|
|
550
574
|
...divStyle,
|
|
551
575
|
border: "var(--bs-border-width) var(--bs-border-style)",
|
|
552
576
|
borderRadius: "var(--bs-border-radius)",
|
|
@@ -555,27 +579,23 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
555
579
|
marginLeft: "10px",
|
|
556
580
|
position: "relative",
|
|
557
581
|
overflowY: "auto",
|
|
558
|
-
}, children:
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
// Only show thinking once streaming is complete
|
|
571
|
-
_jsx(Thinking, { id: id, turns: turns })), isAwaitingLlm && (_jsxs(Box, { id: "awaitingOutputContainer", sx: { display: "flex", alignItems: "center", fontSize: "smaller" }, children: [_jsx("span", { id: "working-span", style: { marginRight: "1rem" }, children: "Working..." }), _jsx(CircularProgress, { id: "awaitingOutputSpinner", sx: {
|
|
572
|
-
color: "var(--bs-primary)",
|
|
573
|
-
}, size: "1rem" })] }))] }), _jsx(ControlButtons, { enableClearChatButton: enableClearChatButton, handleClearChat: handleClearChat, handleSend: handleSend, handleStop: handleStop, isAwaitingLlm: isAwaitingLlm, previousUserQuery: previousUserQuery, shouldEnableRegenerateButton: shouldEnableRegenerateButton })] }));
|
|
582
|
+
}, children: _jsxs(Box, { id: "llm-responses", ref: chatOutputRef, sx: {
|
|
583
|
+
backgroundColor,
|
|
584
|
+
borderRadius: "0.5rem",
|
|
585
|
+
fontSize: "16px",
|
|
586
|
+
overflowY: "auto",
|
|
587
|
+
paddingBottom: "60px",
|
|
588
|
+
paddingLeft: "15px",
|
|
589
|
+
paddingRight: "15px",
|
|
590
|
+
paddingTop: "7.5px",
|
|
591
|
+
scrollbarGutter: "stable",
|
|
592
|
+
width: "100%",
|
|
593
|
+
}, tabIndex: -1, children: [getOptionsMenu(), getOptionsMenuButton(), getChatHistory(), getNetworkIntro(), getAgentGreeting(), _jsx(SampleQueries, { disabled: isAwaitingLlm, handleSend: handleSend, sampleQueries: sampleQueries }), _jsx(Conversation, { id: id, includeAgentMessages: !givesFinalAnswer(selectedNetwork), shouldWrapOutput: shouldWrapOutput, turns: turns }), getThinking(), getWorkingSpinner(), getControlButtons()] }) }));
|
|
574
594
|
const getUserInputBox = () => (_jsxs(Box, { id: "user-input-div", sx: {
|
|
575
595
|
...divStyle,
|
|
596
|
+
alignItems: "center",
|
|
576
597
|
display: "flex",
|
|
577
598
|
margin: "10px",
|
|
578
|
-
alignItems: "flex-end",
|
|
579
599
|
position: "relative",
|
|
580
600
|
}, children: [_jsx(Input, { autoComplete: "off", id: "user-input", multiline: true, placeholder: getPlaceholder(), ref: chatInputRef, sx: {
|
|
581
601
|
border: "var(--bs-border-style) var(--bs-border-width) var(--bs-gray-light)",
|
|
@@ -604,7 +624,7 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
604
624
|
}, sx: {
|
|
605
625
|
color: "var(--bs-primary)",
|
|
606
626
|
opacity: userInputEmpty ? "25%" : "100%",
|
|
607
|
-
}, disabled: userInputEmpty, tabIndex: -1, edge: "end", children: _jsx(ClearIcon, { id: "clear-input-icon" }) })] }) }), _jsx(MicrophoneButton, { isMicOn: isMicOn, onMicToggle: setIsMicOn, speechRecognitionRef: speechRecognitionRef, voiceInputState: voiceInputState
|
|
627
|
+
}, disabled: userInputEmpty, tabIndex: -1, edge: "end", children: _jsx(ClearIcon, { id: "clear-input-icon" }) })] }) }), _jsxs(Box, { sx: { display: "flex", gap: "0.25rem", position: "relative", alignItems: "center" }, children: [_jsx(MicrophoneButton, { isMicOn: isMicOn, onMicToggle: setIsMicOn, setVoiceInputState: setVoiceInputState, speechRecognitionRef: speechRecognitionRef, voiceInputState: voiceInputState }), _jsx(SendButton, { enableSendButton: shouldEnableSendButton, id: "submit-query-button", onClickCallback: () => handleSend(chatInput) })] })] }));
|
|
608
628
|
const getChatBox = () => (_jsxs(Box, { id: `llm-chat-${id}`, sx: {
|
|
609
629
|
display: "flex",
|
|
610
630
|
flexDirection: "column",
|
|
@@ -614,16 +634,23 @@ export const ChatCommon = ({ ref, ...props }) => {
|
|
|
614
634
|
pointerEvents: selectedNetwork ? "auto" : "none",
|
|
615
635
|
position: "relative",
|
|
616
636
|
}, children: [title && getTitle(), getResponseBox(), getUserInputBox()] }));
|
|
637
|
+
const getSelectNetworkOverlayBody = () => (_jsxs(Typography, { component: "span", children: ["Please select a Network from the list to start the chat, or click", _jsx(IconButton, { onClick: () => setSelectedNetwork?.(AGENT_NETWORK_DESIGNER_ID), "aria-label": "select-network-designer", sx: {
|
|
638
|
+
px: 0.5,
|
|
639
|
+
verticalAlign: "middle",
|
|
640
|
+
mb: "4px",
|
|
641
|
+
}, children: _jsx(AddBoxRounded, { sx: {
|
|
642
|
+
color: "var(--bs-secondary)",
|
|
643
|
+
fontSize: "1rem",
|
|
644
|
+
} }) }), "to design your own network!"] }));
|
|
645
|
+
const allApiKeysPresent = missingApiKeys?.length === 0;
|
|
646
|
+
const getMissingApiKeysOverlayBody = () => (_jsx(Typography, { component: "span", children: `API key(s) required for: ${missingApiKeys.join(", ")}. Please add the required key(s) in
|
|
647
|
+
"Settings" to use this Network.` }));
|
|
617
648
|
return (_jsx(Box, { id: `llm-chat-${id}`, sx: {
|
|
618
|
-
display: "flex",
|
|
619
|
-
flexDirection: "column",
|
|
620
|
-
flexGrow: 1,
|
|
621
649
|
height: "100%",
|
|
622
650
|
position: "relative",
|
|
623
651
|
}, children: selectedNetwork
|
|
624
|
-
?
|
|
652
|
+
? allApiKeysPresent
|
|
625
653
|
? getChatBox()
|
|
626
|
-
: getErrorOverlay(
|
|
627
|
-
|
|
628
|
-
: getErrorOverlay("Please select a Network from the list to start the chat.") }));
|
|
654
|
+
: getErrorOverlay(getMissingApiKeysOverlayBody())
|
|
655
|
+
: getErrorOverlay(getSelectNetworkOverlayBody()) }));
|
|
629
656
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const MAX_TURNS = 50;
|
|
@@ -9,7 +9,7 @@ interface ControlButtonsProps {
|
|
|
9
9
|
shouldEnableRegenerateButton: boolean;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
* Generate the Control Buttons for a chat window
|
|
12
|
+
* Generate the Control Buttons for a chat window (resend, clear chat, stop)
|
|
13
13
|
* @returns A fragment containing the Control Buttons.
|
|
14
14
|
*/
|
|
15
15
|
export declare const ControlButtons: FC<ControlButtonsProps>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
/*
|
|
3
3
|
Copyright 2025 Cognizant Technology Solutions Corp, www.cognizant.com.
|
|
4
4
|
|
|
@@ -17,10 +17,13 @@ limitations under the License.
|
|
|
17
17
|
import DeleteOutlined from "@mui/icons-material/DeleteOutlined";
|
|
18
18
|
import Loop from "@mui/icons-material/Loop";
|
|
19
19
|
import StopCircle from "@mui/icons-material/StopCircle";
|
|
20
|
+
import Box from "@mui/material/Box";
|
|
20
21
|
import { SmallLlmChatButton } from "../Common/LlmChatButton.js";
|
|
21
|
-
|
|
22
|
+
//#endregion: Types
|
|
22
23
|
/**
|
|
23
|
-
* Generate the Control Buttons for a chat window
|
|
24
|
+
* Generate the Control Buttons for a chat window (resend, clear chat, stop)
|
|
24
25
|
* @returns A fragment containing the Control Buttons.
|
|
25
26
|
*/
|
|
26
|
-
export const ControlButtons = ({ handleClearChat, enableClearChatButton, isAwaitingLlm, handleSend, handleStop, previousUserQuery, shouldEnableRegenerateButton, }) => (
|
|
27
|
+
export const ControlButtons = ({ handleClearChat, enableClearChatButton, isAwaitingLlm, handleSend, handleStop, previousUserQuery, shouldEnableRegenerateButton, }) => (_jsx(_Fragment, { children: isAwaitingLlm ? (
|
|
28
|
+
// Stop Button
|
|
29
|
+
_jsx(SmallLlmChatButton, { "aria-label": "Stop", disabled: !isAwaitingLlm, id: "stop-output-button", onClick: () => handleStop(), children: _jsx(StopCircle, { fontSize: "small", id: "stop-button-icon" }) })) : (_jsxs(Box, { sx: { display: "flex", gap: 1 }, children: [_jsx(SmallLlmChatButton, { "aria-label": "Clear Chat", disabled: !enableClearChatButton, id: "clear-chat-button", onClick: handleClearChat, children: _jsx(DeleteOutlined, { fontSize: "small", id: "stop-button-icon" }) }), _jsx(SmallLlmChatButton, { "aria-label": "Regenerate", disabled: !shouldEnableRegenerateButton, id: "regenerate-output-button", onClick: () => handleSend(previousUserQuery), children: _jsx(Loop, { fontSize: "small", id: "generate-icon" }) })] })) }));
|
|
@@ -53,6 +53,9 @@ export const FormattedMarkdown = ({ id, nodesList, style, wrapLongLines = false,
|
|
|
53
53
|
// If not, do our best to synthesize a key
|
|
54
54
|
return `${hashString(node?.toString() || "")}-${index}`;
|
|
55
55
|
};
|
|
56
|
+
if (!nodesList || nodesList.length === 0) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
56
59
|
// Walk through the nodes list. If we encounter a string node, we'll aggregate it with other string nodes.
|
|
57
60
|
const formattedOutput = [];
|
|
58
61
|
let currentTextNodes = [];
|
|
@@ -15,14 +15,15 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
import SendIcon from "@mui/icons-material/Send";
|
|
18
|
+
import Tooltip from "@mui/material/Tooltip";
|
|
18
19
|
import { LlmChatButton } from "../Common/LlmChatButton.js";
|
|
19
|
-
|
|
20
|
+
//#endregion: Types
|
|
20
21
|
/**
|
|
21
22
|
* Generate the Send Button for a chat window.
|
|
22
23
|
* @returns The Send Button.
|
|
23
24
|
*/
|
|
24
|
-
export const SendButton = ({ enableSendButton, id, onClickCallback }) => (_jsx(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
export const SendButton = ({ enableSendButton, id, onClickCallback }) => (_jsx(Tooltip, { placement: "top", title: enableSendButton ? "Send" : "Enter a message to enable the send button", children: _jsx("span", { style: {
|
|
26
|
+
display: "inline-block",
|
|
27
|
+
cursor: enableSendButton ? "inherit" : "not-allowed",
|
|
28
|
+
}, children: _jsx(LlmChatButton, { "aria-label": "Send", disabled: !enableSendButton, id: id, onClick: onClickCallback, tabIndex: 0, children: _jsx(SendIcon, { fontSize: "small", id: "stop-button-icon" // Could update this but it would impact QA
|
|
29
|
+
}) }) }) }));
|
|
@@ -17,7 +17,7 @@ limitations under the License.
|
|
|
17
17
|
* List of available hljs themes for the syntax highlighter.
|
|
18
18
|
* See: https://github.com/react-syntax-highlighter/react-syntax-highlighter/blob/master/src/styles/hljs/index.js
|
|
19
19
|
*/
|
|
20
|
-
import { a11yDark, a11yLight, atelierDuneDark, docco } from "react-syntax-highlighter/dist/
|
|
20
|
+
import { a11yDark, a11yLight, atelierDuneDark, docco } from "react-syntax-highlighter/dist/esm/styles/hljs";
|
|
21
21
|
// hljs themes
|
|
22
22
|
export const HLJS_THEMES = {
|
|
23
23
|
a11yDark,
|
|
@@ -3,6 +3,7 @@ import { ConversationTurn } from "./ConversationTurn.js";
|
|
|
3
3
|
interface ThinkingProps {
|
|
4
4
|
readonly id: string;
|
|
5
5
|
readonly turns: ConversationTurn[];
|
|
6
|
+
readonly useNativeNames: boolean;
|
|
6
7
|
}
|
|
7
8
|
/**
|
|
8
9
|
* Component to render the "thinking" section of the chat, which includes all messages from the agent that are
|
|
@@ -6,6 +6,7 @@ import ReactMarkdown from "react-markdown";
|
|
|
6
6
|
import { MessageRole } from "./ConversationTurn.js";
|
|
7
7
|
import { ChatMessageType } from "../../../generated/neuro-san/NeuroSanClient.js";
|
|
8
8
|
import { AccordionLite } from "../../Common/AccordionLite.js";
|
|
9
|
+
import { cleanUpAgentName, removeTrailingUuid } from "../Common/Utils.js";
|
|
9
10
|
/**
|
|
10
11
|
* Set of message types that should be included in the "thinking" section.
|
|
11
12
|
*/
|
|
@@ -15,17 +16,19 @@ const THINKING_MESSAGE_TYPES = new Set([
|
|
|
15
16
|
ChatMessageType.AGENT_PROGRESS,
|
|
16
17
|
ChatMessageType.SYSTEM,
|
|
17
18
|
]);
|
|
18
|
-
const DEFAULT_AGENT_NAME = "
|
|
19
|
-
const formatTurn = (turn) => {
|
|
20
|
-
const
|
|
21
|
-
const
|
|
19
|
+
const DEFAULT_AGENT_NAME = "agent";
|
|
20
|
+
const formatTurn = (turn, useNativeNames) => {
|
|
21
|
+
const agentName = turn.agentName ?? DEFAULT_AGENT_NAME;
|
|
22
|
+
const displayName = useNativeNames ? agentName : cleanUpAgentName(removeTrailingUuid(agentName));
|
|
23
|
+
const headerLine = `**${displayName}**: ${turn.text || ""}`;
|
|
24
|
+
const structureLine = turn.structure == null ? "" : `\n\`${JSON.stringify(turn.structure, null, 2)}\``;
|
|
22
25
|
return `${headerLine}${structureLine}`;
|
|
23
26
|
};
|
|
24
27
|
/**
|
|
25
28
|
* Component to render the "thinking" section of the chat, which includes all messages from the agent that are
|
|
26
29
|
* of a type included in THINKING_MESSAGE_TYPES.
|
|
27
30
|
*/
|
|
28
|
-
export const Thinking = ({ id, turns }) => {
|
|
31
|
+
export const Thinking = ({ id, turns, useNativeNames }) => {
|
|
29
32
|
const thinkingText = useMemo(() => {
|
|
30
33
|
// Find start of latest interaction (most recent user prompt)
|
|
31
34
|
const lastUserTurnIndex = turns.map((t) => t.role).lastIndexOf(MessageRole.User);
|
|
@@ -35,9 +38,9 @@ export const Thinking = ({ id, turns }) => {
|
|
|
35
38
|
.slice(lastUserTurnIndex + 1)
|
|
36
39
|
.filter((turn) => THINKING_MESSAGE_TYPES.has(turn.messageType))
|
|
37
40
|
.filter((turn) => turn.text?.trim().length > 0 || !isEmpty(turn.structure))
|
|
38
|
-
.map((turn) => formatTurn(turn))
|
|
41
|
+
.map((turn) => formatTurn(turn, useNativeNames))
|
|
39
42
|
.join("\n\n");
|
|
40
|
-
}, [turns]);
|
|
43
|
+
}, [turns, useNativeNames]);
|
|
41
44
|
return (thinkingText.length > 0 && (_jsx(AccordionLite, { id: `${id}-thinking`, items: _jsx(Box, { sx: {
|
|
42
45
|
marginLeft: "0.5rem",
|
|
43
46
|
fontSize: "smaller",
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
type LLMChatGroupConfigBtnProps = {
|
|
2
2
|
disabled?: boolean;
|
|
3
|
-
posRight?: number;
|
|
4
|
-
posBottom?: number;
|
|
5
3
|
};
|
|
6
4
|
export declare const LlmChatButton: import("@emotion/styled").StyledComponent<import("@mui/material/Button").ButtonOwnProps & Omit<import("@mui/material/ButtonBase").ButtonBaseOwnProps, keyof import("@mui/material/Button").ButtonOwnProps> & Omit<import("@mui/material/ButtonBase").ButtonBaseOwnProps, "tabIndex" | "type" | "action" | "centerRipple" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "nativeButton" | "onFocusVisible" | "TouchRippleProps" | "touchRippleRef" | keyof import("@mui/material/Button").ButtonOwnProps> & import("@mui/material/OverridableComponent").CommonProps & Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "style" | "children" | "sx" | "className" | "tabIndex" | "color" | "href" | "type" | "classes" | "variant" | "action" | "size" | "disabled" | "centerRipple" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "nativeButton" | "onFocusVisible" | "TouchRippleProps" | "touchRippleRef" | "disableFocusRipple" | "loading" | "loadingIndicator" | "disableElevation" | "endIcon" | "fullWidth" | "loadingPosition" | "startIcon"> & import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles").Theme> & LLMChatGroupConfigBtnProps, {}, {}>;
|
|
7
5
|
export declare const SmallLlmChatButton: import("@emotion/styled").StyledComponent<import("@mui/material/Button").ButtonOwnProps & Omit<import("@mui/material/ButtonBase").ButtonBaseOwnProps, keyof import("@mui/material/Button").ButtonOwnProps> & Omit<import("@mui/material/ButtonBase").ButtonBaseOwnProps, "tabIndex" | "type" | "action" | "centerRipple" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "nativeButton" | "onFocusVisible" | "TouchRippleProps" | "touchRippleRef" | keyof import("@mui/material/Button").ButtonOwnProps> & import("@mui/material/OverridableComponent").CommonProps & Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "style" | "children" | "sx" | "className" | "tabIndex" | "color" | "href" | "type" | "classes" | "variant" | "action" | "size" | "disabled" | "centerRipple" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "nativeButton" | "onFocusVisible" | "TouchRippleProps" | "touchRippleRef" | "disableFocusRipple" | "loading" | "loadingIndicator" | "disableElevation" | "endIcon" | "fullWidth" | "loadingPosition" | "startIcon"> & import("@mui/system").MUIStyledCommonProps<import("@mui/material/styles").Theme> & LLMChatGroupConfigBtnProps, {}, {}>;
|
|
@@ -15,17 +15,14 @@ limitations under the License.
|
|
|
15
15
|
*/
|
|
16
16
|
import Button from "@mui/material/Button";
|
|
17
17
|
import { styled } from "@mui/material/styles";
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
background: `${theme.palette.primary.main} !important`,
|
|
18
|
+
//#endregion: Types
|
|
19
|
+
// In LlmChatButton.tsx
|
|
20
|
+
export const LlmChatButton = styled(Button)(({ disabled, theme }) => ({
|
|
21
|
+
backgroundColor: theme.palette.background.paper,
|
|
23
22
|
borderRadius: "var(--bs-border-radius)",
|
|
24
|
-
|
|
25
|
-
cursor: disabled ? "default" : "pointer",
|
|
23
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
26
24
|
opacity: disabled ? "50%" : "100%",
|
|
27
|
-
|
|
28
|
-
position: "absolute",
|
|
25
|
+
padding: "0.5rem",
|
|
29
26
|
}));
|
|
30
27
|
export const SmallLlmChatButton = styled(LlmChatButton)({
|
|
31
28
|
minWidth: 0,
|
|
@@ -19,7 +19,7 @@ import MicOffIcon from "@mui/icons-material/MicOff";
|
|
|
19
19
|
import Tooltip from "@mui/material/Tooltip";
|
|
20
20
|
import { checkSpeechSupport, toggleListening } from "./VoiceChat.js";
|
|
21
21
|
import { LlmChatButton } from "../Common/LlmChatButton.js";
|
|
22
|
-
|
|
22
|
+
//#endregion: Types
|
|
23
23
|
/**
|
|
24
24
|
* Microphone button component for voice input functionality.
|
|
25
25
|
* Handles toggling voice recognition on/off and displays appropriate visual feedback.
|
|
@@ -42,14 +42,16 @@ export const MicrophoneButton = ({ isMicOn, onMicToggle, speechRecognitionRef, v
|
|
|
42
42
|
await toggleListening(newMicState, speechRecognitionRef.current);
|
|
43
43
|
};
|
|
44
44
|
const isDisabled = !speechSupported;
|
|
45
|
-
const tooltipText =
|
|
46
|
-
?
|
|
47
|
-
: isMicOn
|
|
45
|
+
const tooltipText = speechSupported
|
|
46
|
+
? isMicOn
|
|
48
47
|
? "Turn microphone off"
|
|
49
|
-
: "Turn microphone on"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
: "Turn microphone on"
|
|
49
|
+
: "Voice input is only supported in Google Chrome on Mac or Windows.";
|
|
50
|
+
const isListeningActive = isMicOn && voiceInputState.isListening;
|
|
51
|
+
return (_jsx(Tooltip, { placement: "top", title: tooltipText, children: _jsx("span", { style: {
|
|
52
|
+
display: "inline-block",
|
|
53
|
+
cursor: isDisabled ? "not-allowed" : "inherit",
|
|
54
|
+
}, children: _jsx(LlmChatButton, { "data-testid": "microphone-button", disabled: isDisabled, id: "microphone-button", onClick: handleClick, sx: {
|
|
55
|
+
backgroundColor: isListeningActive ? "success.main" : "background.paper",
|
|
56
|
+
}, tabIndex: 0, children: voiceInputState.isListening ? (_jsx(MicNoneIcon, { "data-testid": "MicNoneIcon", fontSize: "small" })) : (_jsx(MicOffIcon, { "data-testid": "MicOffIcon", fontSize: "small" })) }) }) }));
|
|
55
57
|
};
|