@cognizant-ai-lab/ui-common 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AgentChat/ChatCommon/ChatCommon.d.ts +7 -6
- package/dist/components/AgentChat/ChatCommon/ChatCommon.js +55 -53
- package/dist/components/ChatBot/ChatBot.d.ts +0 -4
- package/dist/components/ChatBot/ChatBot.js +2 -2
- package/dist/components/Common/CustomerLogo.js +1 -3
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +76 -17
- package/dist/components/Settings/ApiKeyInput.d.ts +16 -0
- package/dist/components/Settings/ApiKeyInput.js +70 -0
- package/dist/components/Settings/SettingsDialog.js +30 -3
- package/dist/controller/llm/Providers.d.ts +2 -0
- package/dist/controller/llm/Providers.js +41 -0
- package/dist/state/Settings.d.ts +2 -0
- package/dist/state/Settings.js +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,6 @@ import RestoreIcon from "@mui/icons-material/SettingsBackupRestore";
|
|
|
3
3
|
import Box from "@mui/material/Box";
|
|
4
4
|
import Button from "@mui/material/Button";
|
|
5
5
|
import Checkbox from "@mui/material/Checkbox";
|
|
6
|
-
import CircularProgress from "@mui/material/CircularProgress";
|
|
7
6
|
import Divider from "@mui/material/Divider";
|
|
8
7
|
import FormLabel from "@mui/material/FormLabel";
|
|
9
8
|
import { createTheme, ThemeProvider, useTheme } from "@mui/material/styles";
|
|
@@ -13,8 +12,10 @@ import ToggleButtonGroup from "@mui/material/ToggleButtonGroup";
|
|
|
13
12
|
import Tooltip from "@mui/material/Tooltip";
|
|
14
13
|
import Typography from "@mui/material/Typography";
|
|
15
14
|
import { useEffect, useState } from "react";
|
|
15
|
+
import { ApiKeyInput } from "./ApiKeyInput.js";
|
|
16
16
|
import { FadingCheckmark, useCheckmarkFade } from "./FadingCheckmark.js";
|
|
17
17
|
import { getBrandingSuggestions } from "../../controller/agent/Agent.js";
|
|
18
|
+
import { isAnthropicKeyValid, isOpenAIKeyValid } from "../../controller/llm/Providers.js";
|
|
18
19
|
import { useSettingsStore } from "../../state/Settings.js";
|
|
19
20
|
import { PALETTES } from "../../Theme/Palettes.js";
|
|
20
21
|
import { ConfirmationModal } from "../Common/ConfirmationModal.js";
|
|
@@ -51,6 +52,8 @@ export const SettingsDialog = ({ id, isOpen, logoServiceToken, onClose }) => {
|
|
|
51
52
|
// Zen mode
|
|
52
53
|
const enableZenMode = useSettingsStore((state) => state.settings.behavior.enableZenMode);
|
|
53
54
|
const enableZenModeCheckmark = useCheckmarkFade();
|
|
55
|
+
// API keys
|
|
56
|
+
const apiKeys = useSettingsStore((state) => state.settings.apiKeys);
|
|
54
57
|
// Record user's current theme so at least the settings dialog (with default MUI theme) matches that
|
|
55
58
|
const theme = useTheme();
|
|
56
59
|
const paletteMode = theme.palette.mode;
|
|
@@ -146,12 +149,35 @@ export const SettingsDialog = ({ id, isOpen, logoServiceToken, onClose }) => {
|
|
|
146
149
|
brandingCheckmark.trigger();
|
|
147
150
|
setIsBrandingApplying(false);
|
|
148
151
|
};
|
|
152
|
+
const persistKey = (vendor, key) => {
|
|
153
|
+
updateSettings({
|
|
154
|
+
apiKeys: {
|
|
155
|
+
[vendor]: key,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
};
|
|
149
159
|
// Effect to keep input in sync with state store
|
|
150
160
|
useEffect(() => {
|
|
151
161
|
setCustomerInput(customer ?? "");
|
|
152
162
|
}, [customer]);
|
|
153
163
|
const availablePalettes = customer && brandingRangePalette?.length > 0 ? { brand: brandingRangePalette } : PALETTES;
|
|
154
164
|
const paletteKeys = Object.keys(availablePalettes);
|
|
165
|
+
const apiKeyConfigs = [
|
|
166
|
+
{
|
|
167
|
+
vendor: "OpenAI",
|
|
168
|
+
idSuffix: "openai",
|
|
169
|
+
logo: theme.palette.mode === "dark" ? "/OpenAI-white.png" : "/OpenAI-black.png",
|
|
170
|
+
onTest: isOpenAIKeyValid,
|
|
171
|
+
placeholder: "sk-...",
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
vendor: "Anthropic",
|
|
175
|
+
idSuffix: "anthropic",
|
|
176
|
+
logo: "/claude.png",
|
|
177
|
+
onTest: isAnthropicKeyValid,
|
|
178
|
+
placeholder: "sk-ant-...",
|
|
179
|
+
},
|
|
180
|
+
];
|
|
155
181
|
/* Dev note:
|
|
156
182
|
Before you go removing the "useless" spans in code below that wrap MUI elements: they are required because
|
|
157
183
|
MUI's disabled state on certain components sets pointer-events: none, which prevents tooltips from working.
|
|
@@ -176,7 +202,8 @@ export const SettingsDialog = ({ id, isOpen, logoServiceToken, onClose }) => {
|
|
|
176
202
|
minWidth: "50%",
|
|
177
203
|
minHeight: "50%",
|
|
178
204
|
border: "1px solid",
|
|
179
|
-
}, children: [_jsxs(Box, { sx: { marginBottom: 3 }, children: [_jsx(Typography, { variant: "h6", sx: { marginBottom: 1 }, children: "
|
|
205
|
+
}, children: [_jsxs(Box, { sx: { marginBottom: 3 }, children: [_jsx(Typography, { variant: "h6", sx: { marginBottom: 1 }, children: "API Keys" }), _jsx(Box, { sx: { display: "flex", flexDirection: "column", gap: 1.5 }, children: apiKeyConfigs.map(({ vendor, idSuffix, logo, onTest, placeholder }) => (_jsx(ApiKeyInput, { forgetKey: () => persistKey(vendor, ""), id: `${id}-${idSuffix}`, logo: logo, onSave: (key) => persistKey(vendor, key), onTest: onTest, persistedValue: apiKeys[vendor], placeholder: placeholder, vendor: vendor }, idSuffix))) })] }), _jsxs(Box, { sx: { marginBottom: 3 }, children: [_jsx(Typography, { variant: "h6", sx: { marginBottom: 1 }, children: "Behavior" }), _jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [_jsx(FormLabel, { children: "Enable \"Zen\" mode:" }), _jsx(Tooltip, { title: "Hides most of the UI during agent network animations, " +
|
|
206
|
+
"providing a more immersive experience.", children: _jsx(Checkbox, { checked: enableZenMode, "data-testid": "zen-mode-checkbox", onChange: (_, checked) => {
|
|
180
207
|
updateSettings({ behavior: { enableZenMode: checked } });
|
|
181
208
|
enableZenModeCheckmark.trigger();
|
|
182
209
|
} }) }), _jsx(FadingCheckmark, { show: enableZenModeCheckmark.show })] })] }), _jsxs(Box, { sx: { marginBottom: 3 }, children: [_jsx(Typography, { variant: "h6", sx: { marginBottom: 1 }, children: "Appearance" }), _jsx(Typography, { variant: "subtitle1", sx: { marginBottom: 1, marginTop: 2, fontWeight: 600 }, children: "Branding" }), _jsx(Divider, { sx: { marginBottom: 2 } }), _jsx(Box, { sx: { display: "flex", alignItems: "center" }, children: _jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 2, marginBottom: "1rem", width: "100%" }, children: [_jsx(FormLabel, { children: "Customer:" }), _jsx(TextField, { "aria-label": "branding-input", onChange: (e) => setCustomerInput(e.target.value), onKeyDown: (e) => {
|
|
@@ -185,7 +212,7 @@ export const SettingsDialog = ({ id, isOpen, logoServiceToken, onClose }) => {
|
|
|
185
212
|
}
|
|
186
213
|
}, value: customerInput ?? "", placeholder: "Company or organization name", size: "small", sx: { width: "100%" }, variant: "outlined" }), _jsx(Button, { disabled: customerInput?.trim().length === 0 ||
|
|
187
214
|
isBrandingApplying ||
|
|
188
|
-
customerInput === customer, variant: "contained", size: "small", onClick: handleBrandingApply,
|
|
215
|
+
customerInput === customer, variant: "contained", size: "small", onClick: handleBrandingApply, loading: isBrandingApplying, sx: { minWidth: "8rem" }, children: "Apply" }), _jsx(FadingCheckmark, { show: brandingCheckmark.show })] }) }), _jsx(Box, { sx: { display: "flex", alignItems: "center" }, children: _jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 2, marginBottom: "1rem", width: "100%" }, children: [_jsx(FormLabel, { children: "Logo:" }), _jsx(Tooltip, { title: customer ? null : "Set a customer name to enable logo options", children: _jsx("span", { children: _jsxs(ToggleButtonGroup, { "aria-label": "logo-selection", disabled: !customer, exclusive: true, onChange: (_, value) => {
|
|
189
216
|
if (value !== null) {
|
|
190
217
|
updateSettings({
|
|
191
218
|
branding: {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export const isOpenAIKeyValid = async (key) => {
|
|
2
|
+
try {
|
|
3
|
+
// Just call the "list models" API with the supplied key.
|
|
4
|
+
// We don't care about the result, just whether it succeeds or not
|
|
5
|
+
const res = await fetch("https://api.openai.com/v1/models", {
|
|
6
|
+
method: "GET",
|
|
7
|
+
headers: {
|
|
8
|
+
Accept: "application/json",
|
|
9
|
+
Authorization: `Bearer ${key}`,
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
return res.ok;
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
console.error("Error validating API key:", e);
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
export const isAnthropicKeyValid = async (key) => {
|
|
20
|
+
try {
|
|
21
|
+
// Just call the "list models" API with the supplied key.
|
|
22
|
+
// We don't care about the result, just whether it succeeds or not
|
|
23
|
+
const res = await fetch("https://api.anthropic.com/v1/models", {
|
|
24
|
+
method: "GET",
|
|
25
|
+
headers: {
|
|
26
|
+
Accept: "application/json",
|
|
27
|
+
"anthropic-version": "2023-06-01",
|
|
28
|
+
"X-Api-Key": key,
|
|
29
|
+
// Request vendor to allow CORS for this endpoint
|
|
30
|
+
// Reference: https://simonwillison.net/2024/Aug/23/anthropic-dangerous-direct-browser-access/
|
|
31
|
+
// The request will be rejected without this.
|
|
32
|
+
"anthropic-dangerous-direct-browser-access": "true",
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
return res.ok;
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
console.error("Error validating API key:", e);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
};
|
package/dist/state/Settings.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { PaletteKey } from "../Theme/Palettes.js";
|
|
|
9
9
|
type DeepPartial<T> = {
|
|
10
10
|
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
|
|
11
11
|
};
|
|
12
|
+
export type LLMProvider = "OpenAI" | "Anthropic";
|
|
12
13
|
/**
|
|
13
14
|
* User preference settings
|
|
14
15
|
*/
|
|
@@ -32,6 +33,7 @@ interface Settings {
|
|
|
32
33
|
readonly behavior: {
|
|
33
34
|
readonly enableZenMode: boolean;
|
|
34
35
|
};
|
|
36
|
+
readonly apiKeys: Partial<Record<LLMProvider, string>>;
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
37
39
|
* Zustand state store for user preferences/Settings
|