@cognizant-ai-lab/ui-common 1.8.0 → 1.10.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/README.md +3 -3
- package/dist/components/AgentChat/ChatCommon/ChatCommon.d.ts +9 -3
- package/dist/components/AgentChat/ChatCommon/ChatCommon.js +94 -27
- package/dist/components/AgentChat/ChatCommon/ChatHistory.d.ts +7 -0
- package/dist/components/AgentChat/ChatCommon/ChatHistory.js +1 -1
- package/dist/components/AgentChat/ChatCommon/ControlButtons.d.ts +4 -2
- package/dist/components/AgentChat/ChatCommon/ControlButtons.js +8 -2
- package/dist/components/AgentChat/ChatCommon/ConversationTurn.d.ts +5 -5
- package/dist/components/AgentChat/ChatCommon/ConversationTurn.js +1 -0
- package/dist/components/AgentChat/ChatCommon/Thinking.js +2 -2
- package/dist/components/AgentChat/Common/Utils.d.ts +0 -7
- package/dist/components/AgentChat/Common/Utils.js +0 -12
- package/dist/components/Common/Breadcrumbs.js +1 -1
- package/dist/components/Common/Footer.js +4 -0
- package/dist/components/Common/notification.d.ts +4 -4
- package/dist/components/MultiAgentAccelerator/{AgentFlow.d.ts → AgentFlow/AgentFlow.d.ts} +15 -5
- package/dist/components/MultiAgentAccelerator/{AgentFlow.js → AgentFlow/AgentFlow.js} +99 -58
- package/dist/components/MultiAgentAccelerator/{AgentNode.d.ts → AgentFlow/AgentNode.d.ts} +1 -1
- package/dist/components/MultiAgentAccelerator/{AgentNode.js → AgentFlow/AgentNode.js} +11 -9
- package/dist/components/MultiAgentAccelerator/{GraphLayouts.d.ts → AgentFlow/GraphLayouts.d.ts} +4 -4
- package/dist/components/MultiAgentAccelerator/{GraphLayouts.js → AgentFlow/GraphLayouts.js} +15 -41
- package/dist/components/MultiAgentAccelerator/AgentFlow/GraphStructure.d.ts +21 -0
- package/dist/components/MultiAgentAccelerator/AgentFlow/GraphStructure.js +27 -0
- package/dist/components/MultiAgentAccelerator/AgentFlow/PlasmaEdge.d.ts +7 -0
- package/dist/components/MultiAgentAccelerator/{PlasmaEdge.js → AgentFlow/PlasmaEdge.js} +13 -8
- package/dist/components/MultiAgentAccelerator/MultiAgentAccelerator.js +74 -83
- package/dist/components/MultiAgentAccelerator/Schema/SlyData.d.ts +17 -0
- package/dist/components/MultiAgentAccelerator/Schema/SlyData.js +23 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.d.ts +2 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/AgentNetworkTreeItem.js +22 -25
- package/dist/components/MultiAgentAccelerator/Sidebar/Sidebar.js +16 -22
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.d.ts +1 -0
- package/dist/components/MultiAgentAccelerator/Sidebar/TreeBuilder.js +27 -7
- package/dist/components/MultiAgentAccelerator/TemporaryNetworks.d.ts +8 -0
- package/dist/components/MultiAgentAccelerator/TemporaryNetworks.js +61 -13
- package/dist/components/MultiAgentAccelerator/{ThoughtBubbleEdge.d.ts → ThoughtBubbles/ThoughtBubbleEdge.d.ts} +1 -1
- package/dist/components/MultiAgentAccelerator/{ThoughtBubbleOverlay.js → ThoughtBubbles/ThoughtBubbleOverlay.js} +1 -1
- package/dist/components/MultiAgentAccelerator/Tour/MainTourSteps.js +7 -2
- package/dist/components/MultiAgentAccelerator/const.d.ts +11 -10
- package/dist/components/MultiAgentAccelerator/const.js +22 -20
- package/dist/components/Settings/SettingsDialog.js +26 -10
- package/dist/controller/agent/Agent.d.ts +14 -6
- package/dist/controller/agent/Agent.js +18 -14
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/state/Settings.d.ts +81 -4
- package/dist/state/Settings.js +87 -7
- package/dist/state/TemporaryNetworks.js +12 -21
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/utils/AgentName.d.ts +17 -0
- package/dist/utils/AgentName.js +46 -0
- package/dist/utils/BrowserNavigation.js +2 -0
- package/dist/utils/File.d.ts +4 -1
- package/dist/utils/File.js +4 -9
- package/dist/utils/text.js +3 -7
- package/package.json +9 -10
- package/dist/components/MultiAgentAccelerator/PlasmaEdge.d.ts +0 -3
- /package/dist/components/MultiAgentAccelerator/{ThoughtBubbleEdge.js → ThoughtBubbles/ThoughtBubbleEdge.js} +0 -0
- /package/dist/components/MultiAgentAccelerator/{ThoughtBubbleOverlay.d.ts → ThoughtBubbles/ThoughtBubbleOverlay.d.ts} +0 -0
|
@@ -62,3 +62,11 @@ export declare const isTemporaryNetwork: (agentName: string | null, networks: Te
|
|
|
62
62
|
* Returns a new array; does not mutate either argument.
|
|
63
63
|
*/
|
|
64
64
|
export declare const mergeNetworks: (target: TemporaryNetwork[], incoming: TemporaryNetwork[]) => TemporaryNetwork[];
|
|
65
|
+
/** Logs and notifies about a save error. Suppresses AbortError (user-canceled). */
|
|
66
|
+
export declare const notifySaveError: (agentName: string, e: unknown) => void;
|
|
67
|
+
/**
|
|
68
|
+
* Streams a network definition through the network designer to obtain its reservation.
|
|
69
|
+
* Returns the single updated network as a one-element list (empty if the designer returned
|
|
70
|
+
* no reservation).
|
|
71
|
+
*/
|
|
72
|
+
export declare const streamNetworkDesignerUpsert: (neuroSanURL: string, signal: AbortSignal, frontman: string, networkDef: AgentNetworkDefinitionEntry[], agentNetworkName: string | undefined, username: string) => Promise<TemporaryNetwork[]>;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { keyBy, mergeWith } from "lodash-es";
|
|
1
2
|
import { AGENT_NETWORK_DEFINITION_KEY, AGENT_NETWORK_HOCON, AGENT_RESERVATIONS_KEY, DisplayAs, TEMPORARY_NETWORK_FOLDER, } from "./const.js";
|
|
3
|
+
import { sendNetworkDesignerRequest } from "../../controller/agent/Agent.js";
|
|
2
4
|
import { ChatMessageType } from "../../generated/neuro-san/NeuroSanClient.js";
|
|
3
|
-
import { removeTrailingUuid } from "
|
|
5
|
+
import { removeTrailingUuid } from "../../utils/AgentName.js";
|
|
6
|
+
import { chatMessageFromChunk } from "../AgentChat/Common/Utils.js";
|
|
7
|
+
import { NotificationType, sendNotification } from "../Common/notification.js";
|
|
8
|
+
//#endregion: Types
|
|
4
9
|
/**
|
|
5
10
|
* Extracts agent reservations from a chat message, if they exist.
|
|
6
11
|
* @param message The chat message to extract reservations from. We expect reservations to be present in messages of
|
|
@@ -44,7 +49,11 @@ export const extractNetworkHocon = (message) => {
|
|
|
44
49
|
* @returns List of TemporaryNetwork objects ready for the store.
|
|
45
50
|
*/
|
|
46
51
|
export const convertReservationsToNetworks = (agentReservations, networkHocon, agentNetworkDefinition, agentNetworkName) => {
|
|
47
|
-
return agentReservations
|
|
52
|
+
return (agentReservations
|
|
53
|
+
// reservation_id is typed as required but is echoed from un-vetted backend data; skip entries
|
|
54
|
+
// missing it rather than build a "temporary/undefined" network.
|
|
55
|
+
.filter((reservation) => Boolean(reservation?.reservation_id))
|
|
56
|
+
.map((reservation) => ({
|
|
48
57
|
reservation,
|
|
49
58
|
agentInfo: {
|
|
50
59
|
agent_name: `${TEMPORARY_NETWORK_FOLDER}/${reservation.reservation_id}`,
|
|
@@ -54,7 +63,7 @@ export const convertReservationsToNetworks = (agentReservations, networkHocon, a
|
|
|
54
63
|
agentNetworkName: agentNetworkName ?? removeTrailingUuid(reservation.reservation_id),
|
|
55
64
|
networkHocon,
|
|
56
65
|
agentNetworkDefinition,
|
|
57
|
-
}));
|
|
66
|
+
})));
|
|
58
67
|
};
|
|
59
68
|
export const isEditableAgent = (displayAs) => displayAs === DisplayAs.LLM_AGENT;
|
|
60
69
|
/**
|
|
@@ -82,14 +91,53 @@ export const isTemporaryNetwork = (agentName, networks) => agentName !== null &&
|
|
|
82
91
|
* Merges incoming networks into target, keeping the entry with the highest expiration time.
|
|
83
92
|
* Returns a new array; does not mutate either argument.
|
|
84
93
|
*/
|
|
85
|
-
export const mergeNetworks = (target, incoming) =>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
export const mergeNetworks = (target, incoming) => Object.values(mergeWith(keyBy(target, "agentNetworkName"), keyBy(incoming, "agentNetworkName"),
|
|
95
|
+
// Both collections share a name: keep whichever reservation expires later, existing wins ties.
|
|
96
|
+
(existing, candidate) => existing &&
|
|
97
|
+
existing.reservation.expiration_time_in_seconds >= candidate.reservation.expiration_time_in_seconds
|
|
98
|
+
? existing
|
|
99
|
+
: candidate));
|
|
100
|
+
/**
|
|
101
|
+
* Extracts TemporaryNetworks from a single streamed chunk, merging into `accumulated`.
|
|
102
|
+
* Returns `accumulated` unchanged if the chunk yields no reservations or on parse error.
|
|
103
|
+
*/
|
|
104
|
+
const collectNetworkFromChunk = (chunk, updated, accumulated) => {
|
|
105
|
+
try {
|
|
106
|
+
const chatMessage = chatMessageFromChunk(chunk);
|
|
107
|
+
if (!chatMessage)
|
|
108
|
+
return accumulated;
|
|
109
|
+
// Always use the user's edited definition as the authoritative value.
|
|
110
|
+
const converted = extractTemporaryNetworksFromMessage(chatMessage, updated);
|
|
111
|
+
if (converted.length === 0)
|
|
112
|
+
return accumulated;
|
|
113
|
+
return mergeNetworks(accumulated, converted);
|
|
93
114
|
}
|
|
94
|
-
|
|
95
|
-
|
|
115
|
+
catch (e) {
|
|
116
|
+
console.warn("Failed to process chunk from network designer:", e);
|
|
117
|
+
return accumulated;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
/** Logs and notifies about a save error. Suppresses AbortError (user-canceled). */
|
|
121
|
+
export const notifySaveError = (agentName, e) => {
|
|
122
|
+
if (e instanceof DOMException && e.name === "AbortError")
|
|
123
|
+
return;
|
|
124
|
+
console.error("Failed to submit agent network update:", e);
|
|
125
|
+
const detail = e instanceof DOMException && e.name === "TimeoutError"
|
|
126
|
+
? "The request timed out waiting for the server. Please try again."
|
|
127
|
+
: String(e);
|
|
128
|
+
sendNotification(NotificationType.error, `Failed to update network "${agentName}".`, detail);
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Streams a network definition through the network designer to obtain its reservation.
|
|
132
|
+
* Returns the single updated network as a one-element list (empty if the designer returned
|
|
133
|
+
* no reservation).
|
|
134
|
+
*/
|
|
135
|
+
export const streamNetworkDesignerUpsert = async (neuroSanURL, signal, frontman, networkDef, agentNetworkName, username) => {
|
|
136
|
+
let newNetworks = [];
|
|
137
|
+
await sendNetworkDesignerRequest(neuroSanURL, signal, frontman, networkDef, agentNetworkName, username, (chunk) => {
|
|
138
|
+
// There is only one network. The designer echoes it across streamed chunks. Merge by name so the
|
|
139
|
+
// repeated echoes collapse into that single entry rather than appending duplicates.
|
|
140
|
+
newNetworks = collectNetworkFromChunk(chunk, networkDef, newNetworks);
|
|
141
|
+
});
|
|
142
|
+
return newNetworks;
|
|
143
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Edge, EdgeProps } from "@xyflow/react";
|
|
2
2
|
import { FC } from "react";
|
|
3
|
-
import { ChatMessageType } from "
|
|
3
|
+
import { ChatMessageType } from "../../../generated/neuro-san/NeuroSanClient.js";
|
|
4
4
|
interface ThoughtBubbleEdgeData extends Record<string, unknown> {
|
|
5
5
|
text?: string;
|
|
6
6
|
showAlways?: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { styled } from "@mui/material/styles";
|
|
3
3
|
import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
-
import { ChatMessageType } from "
|
|
4
|
+
import { ChatMessageType } from "../../../generated/neuro-san/NeuroSanClient.js";
|
|
5
5
|
// #endregion: Types
|
|
6
6
|
// #region: Constants
|
|
7
7
|
const BUBBLE_DISTANCE_FROM_RIGHT_EDGE = 20; // Fixed distance from right edge
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
2
|
/**
|
|
2
3
|
* This file defines the steps for the main tour of the Multi-Agent Accelerator application.
|
|
3
4
|
*
|
|
@@ -18,8 +19,7 @@ export const MAIN_TOUR_STEPS = [
|
|
|
18
19
|
placement: "bottom",
|
|
19
20
|
},
|
|
20
21
|
{
|
|
21
|
-
content: "Agent Network Designer: Click here to create and edit your own network, with the help of a "
|
|
22
|
-
"powerful AI assistant.",
|
|
22
|
+
content: (_jsxs(_Fragment, { children: ["Agent Network Designer: Click here to create and edit your own network, with the help of a powerful AI assistant.", _jsx("br", {}), _jsx("br", {}), "Networks you create can be downloaded from the sidebar as a HOCON file and run in neuro-san or neuro-san-studio. See the User Guide (under Help) for more information."] })),
|
|
23
23
|
target: () => document.querySelector("#add-network-icon"),
|
|
24
24
|
placement: "bottom",
|
|
25
25
|
},
|
|
@@ -67,6 +67,11 @@ export const MAIN_TOUR_STEPS = [
|
|
|
67
67
|
target: () => document.querySelector("#agent-network-ui-options-menu-button-container"),
|
|
68
68
|
placement: "bottom",
|
|
69
69
|
},
|
|
70
|
+
{
|
|
71
|
+
content: "This button allows you to download the chat with this agent, including history, as a plain text file.",
|
|
72
|
+
target: () => document.querySelector("#save-chat-button"),
|
|
73
|
+
placement: "bottom",
|
|
74
|
+
},
|
|
70
75
|
{
|
|
71
76
|
content: "Access Settings from this icon. Here you can change the look and feel of the application, including " +
|
|
72
77
|
"auto branding for a particular customer, enter API keys for providers like OpenAI and Anthropic, and " +
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import { ConnectivityInfo } from "../../generated/neuro-san/NeuroSanClient.js";
|
|
2
|
-
export declare const DEFAULT_FRONTMAN_X_POS = 150;
|
|
3
|
-
export declare const DEFAULT_FRONTMAN_Y_POS = 450;
|
|
4
|
-
export declare const BASE_RADIUS = 100;
|
|
5
|
-
export declare const LEVEL_SPACING = 150;
|
|
6
|
-
export declare const TEMPORARY_NETWORK_FOLDER = "temporary";
|
|
7
|
-
export declare const AGENT_RESERVATIONS_KEY = "agent_reservations";
|
|
8
|
-
export declare const AGENT_NETWORK_HOCON = "agent_network_hocon_text";
|
|
9
|
-
export declare const AGENT_PROGRESS_CONNECTIVITY_KEY = "connectivity_info";
|
|
10
|
-
export declare const AGENT_NETWORK_DESIGNER_ID = "agent_network_designer";
|
|
11
2
|
export declare const AGENT_NETWORK_DEFINITION_KEY = "agent_network_definition";
|
|
3
|
+
export declare const AGENT_NETWORK_DESIGNER_ID = "agent_network_designer";
|
|
4
|
+
export declare const AGENT_NETWORK_HOCON = "agent_network_hocon_text";
|
|
12
5
|
export declare const AGENT_NETWORK_NAME_KEY = "agent_network_name";
|
|
13
|
-
export declare const
|
|
6
|
+
export declare const AGENT_PROGRESS_CONNECTIVITY_KEY = "connectivity_info";
|
|
7
|
+
export declare const AGENT_RESERVATIONS_KEY = "agent_reservations";
|
|
14
8
|
/**
|
|
15
9
|
* A single agent entry within an agent network definition, as received in sly_data from the backend.
|
|
16
10
|
* Extends ConnectivityInfo with editable instructions and description fields for the Agent Network Designer.
|
|
@@ -19,6 +13,9 @@ export type AgentNetworkDefinitionEntry = ConnectivityInfo & {
|
|
|
19
13
|
readonly instructions?: string;
|
|
20
14
|
readonly description?: string;
|
|
21
15
|
};
|
|
16
|
+
export declare const BASE_RADIUS = 100;
|
|
17
|
+
export declare const DEFAULT_FRONTMAN_X_POS = 150;
|
|
18
|
+
export declare const DEFAULT_FRONTMAN_Y_POS = 450;
|
|
22
19
|
/** Possible values for the `display_as` field in ConnectivityInfo / AgentNetworkDefinitionEntry. */
|
|
23
20
|
export declare enum DisplayAs {
|
|
24
21
|
LLM_AGENT = "llm_agent",
|
|
@@ -26,5 +23,9 @@ export declare enum DisplayAs {
|
|
|
26
23
|
LANGCHAIN_TOOL = "langchain_tool",
|
|
27
24
|
EXTERNAL_AGENT = "external_agent"
|
|
28
25
|
}
|
|
26
|
+
export declare const EXPIRED_NETWORKS_CHECK_INTERVAL_MS: number;
|
|
29
27
|
export declare const GRACE_PERIOD_MS: number;
|
|
28
|
+
export declare const LEVEL_SPACING = 150;
|
|
30
29
|
export declare const SHOW_TOUR_DELAY_MS = 5000;
|
|
30
|
+
export declare const TEMPORARY_NETWORK_FOLDER = "temporary";
|
|
31
|
+
export declare const TRIGGER_APP_TOUR_EVENT_NAME = "trigger-app-tour";
|
|
@@ -13,30 +13,22 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
export const DEFAULT_FRONTMAN_X_POS = 150;
|
|
17
|
-
export const DEFAULT_FRONTMAN_Y_POS = 450;
|
|
18
|
-
// Minimum distance from center
|
|
19
|
-
export const BASE_RADIUS = 100;
|
|
20
|
-
// Distance between depth levels
|
|
21
|
-
export const LEVEL_SPACING = 150;
|
|
22
|
-
// Temporary folder name for networks created from agent reservations. These networks are not "in a folder" when
|
|
23
|
-
// they come from the backend, but we need to put them somewhere in the UI, and this makes it clear that they're
|
|
24
|
-
// temporary.
|
|
25
|
-
export const TEMPORARY_NETWORK_FOLDER = "temporary";
|
|
26
|
-
// We expect the agent reservations to be stored in sly_data under this key
|
|
27
|
-
export const AGENT_RESERVATIONS_KEY = "agent_reservations";
|
|
28
|
-
// We expect the agent network HOCON to be stored in sly_data under this key, if it is provided by the backend
|
|
29
|
-
export const AGENT_NETWORK_HOCON = "agent_network_hocon_text";
|
|
30
|
-
// The key in the message structure where connectivity info is stored for agent progress messages
|
|
31
|
-
export const AGENT_PROGRESS_CONNECTIVITY_KEY = "connectivity_info";
|
|
32
|
-
// Agent name for the special "Agent Network Designer" network
|
|
33
|
-
export const AGENT_NETWORK_DESIGNER_ID = "agent_network_designer";
|
|
34
16
|
// The key in sly_data where the agent network definition is stored
|
|
35
17
|
export const AGENT_NETWORK_DEFINITION_KEY = "agent_network_definition";
|
|
18
|
+
// Agent name for the special "Agent Network Designer" network
|
|
19
|
+
export const AGENT_NETWORK_DESIGNER_ID = "agent_network_designer";
|
|
20
|
+
// We expect the agent network HOCON to be stored in sly_data under this key, if it is provided by the backend
|
|
21
|
+
export const AGENT_NETWORK_HOCON = "agent_network_hocon_text";
|
|
36
22
|
// The key in sly_data where the agent network name is stored
|
|
37
23
|
export const AGENT_NETWORK_NAME_KEY = "agent_network_name";
|
|
38
|
-
// The
|
|
39
|
-
export const
|
|
24
|
+
// The key in the message structure where connectivity info is stored for agent progress messages
|
|
25
|
+
export const AGENT_PROGRESS_CONNECTIVITY_KEY = "connectivity_info";
|
|
26
|
+
// We expect the agent reservations to be stored in sly_data under this key
|
|
27
|
+
export const AGENT_RESERVATIONS_KEY = "agent_reservations";
|
|
28
|
+
// Minimum distance from center
|
|
29
|
+
export const BASE_RADIUS = 100;
|
|
30
|
+
export const DEFAULT_FRONTMAN_X_POS = 150;
|
|
31
|
+
export const DEFAULT_FRONTMAN_Y_POS = 450;
|
|
40
32
|
/** Possible values for the `display_as` field in ConnectivityInfo / AgentNetworkDefinitionEntry. */
|
|
41
33
|
export var DisplayAs;
|
|
42
34
|
(function (DisplayAs) {
|
|
@@ -45,7 +37,17 @@ export var DisplayAs;
|
|
|
45
37
|
DisplayAs["LANGCHAIN_TOOL"] = "langchain_tool";
|
|
46
38
|
DisplayAs["EXTERNAL_AGENT"] = "external_agent";
|
|
47
39
|
})(DisplayAs || (DisplayAs = {}));
|
|
40
|
+
// Check for expired networks every this many milliseconds
|
|
41
|
+
export const EXPIRED_NETWORKS_CHECK_INTERVAL_MS = 10 * 1000;
|
|
48
42
|
// Display expired temporary networks for this amount of time after they expire so users can see what happened
|
|
49
43
|
export const GRACE_PERIOD_MS = 5 * 60 * 1000; // 5 minutes
|
|
44
|
+
// Distance between depth levels
|
|
45
|
+
export const LEVEL_SPACING = 150;
|
|
50
46
|
// We show the tour modal after this amount of time so as not to "pounce" on the user when they first open the app
|
|
51
47
|
export const SHOW_TOUR_DELAY_MS = 5000;
|
|
48
|
+
// Temporary folder name for networks created from agent reservations. These networks are not "in a folder" when
|
|
49
|
+
// they come from the backend, but we need to put them somewhere in the UI, and this makes it clear that they're
|
|
50
|
+
// temporary.
|
|
51
|
+
export const TEMPORARY_NETWORK_FOLDER = "temporary";
|
|
52
|
+
// The event name that needs to be fired for the app tour to start
|
|
53
|
+
export const TRIGGER_APP_TOUR_EVENT_NAME = "trigger-app-tour";
|
|
@@ -19,12 +19,11 @@ import Typography from "@mui/material/Typography";
|
|
|
19
19
|
import { useEffect, useMemo, useState, } from "react";
|
|
20
20
|
import { ApiKeyInput } from "./ApiKeyInput.js";
|
|
21
21
|
import { useCheckmarkFade } from "./FadingCheckmark.js";
|
|
22
|
-
import InfoTip from "./InfoTip.js";
|
|
23
22
|
import { SettingsRow } from "./SettingsRow.js";
|
|
24
23
|
import { getBrandingSuggestions, testConnection } from "../../controller/agent/Agent.js";
|
|
25
24
|
import { isAnthropicKeyValid, isOpenAIKeyValid } from "../../controller/llm/Providers.js";
|
|
26
25
|
import { useEnvironmentStore } from "../../state/Environment.js";
|
|
27
|
-
import { DEFAULT_SETTINGS, useSettingsStore } from "../../state/Settings.js";
|
|
26
|
+
import { API_KEYS_TTL_MS, DEFAULT_SETTINGS, getApiKey, useSettingsStore, } from "../../state/Settings.js";
|
|
28
27
|
import { PALETTES } from "../../Theme/Palettes.js";
|
|
29
28
|
import { ConfirmationModal } from "../Common/ConfirmationModal.js";
|
|
30
29
|
import { MUIDialog } from "../Common/MUIDialog.js";
|
|
@@ -40,7 +39,7 @@ const Section = styled(Box)(({ theme }) => ({
|
|
|
40
39
|
display: "flex",
|
|
41
40
|
flexDirection: "column",
|
|
42
41
|
gap: theme.spacing(2),
|
|
43
|
-
marginBottom: theme.spacing(
|
|
42
|
+
marginBottom: theme.spacing(2),
|
|
44
43
|
}));
|
|
45
44
|
const SubsectionTitle = styled(Typography)(({ theme }) => ({
|
|
46
45
|
borderBottom: `1px solid ${theme.palette.divider}`,
|
|
@@ -235,10 +234,20 @@ export const SettingsDialog = ({ id, isOpen, logoServiceToken, onClose }) => {
|
|
|
235
234
|
brandingCheckmark.trigger();
|
|
236
235
|
logoCheckmark.trigger();
|
|
237
236
|
};
|
|
238
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Used for both saving and removing keys.
|
|
239
|
+
* @param vendor Vendor for this key: see the list in LLMProvider type
|
|
240
|
+
* @param key Value of the key
|
|
241
|
+
* @param checkmark Checkmark to trigger on save
|
|
242
|
+
* @param now Timestamp for "now"
|
|
243
|
+
*/
|
|
244
|
+
const persistKey = (vendor, key, checkmark, now) => {
|
|
239
245
|
updateSettings({
|
|
240
246
|
apiKeys: {
|
|
241
|
-
[vendor]:
|
|
247
|
+
[vendor]: {
|
|
248
|
+
value: key,
|
|
249
|
+
expiresAt: key ? now + API_KEYS_TTL_MS : 0,
|
|
250
|
+
},
|
|
242
251
|
},
|
|
243
252
|
});
|
|
244
253
|
checkmark.trigger();
|
|
@@ -324,9 +333,17 @@ export const SettingsDialog = ({ id, isOpen, logoServiceToken, onClose }) => {
|
|
|
324
333
|
}, sx: { flex: 1 }, value: neuroSanUrlInput }), _jsx(StatusLight, { id: `${id}-status-light`, statusValue: statusLightValue }), _jsx(Button, { disabled: neuroSanUrlInput.trim().length === 0, onClick: handleTestConnection, size: "small", variant: "contained", children: "Test" }), _jsx(Button, { disabled: neuroSanUrlSaveDisabled, onClick: handleSaveNeuroSanUrl, size: "small", variant: "contained", children: "Save" }), _jsx(Button, { disabled: neuroSanUrlResetDisabled, onClick: handleResetNeuroSanUrl, size: "small", variant: "contained", children: "Default" })] }, `${id}-neuro-san-server-url`) }));
|
|
325
334
|
};
|
|
326
335
|
const getServicesSection = () => (_jsxs(Section, { children: [_jsx(SettingsSectionTitle, { children: "External Services" }), getNeuroSanSubsection()] }));
|
|
327
|
-
const getApiKeysSection = () => (_jsxs(Section, { children: [_jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: theme.spacing(
|
|
328
|
-
|
|
329
|
-
|
|
336
|
+
const getApiKeysSection = () => (_jsxs(Section, { children: [_jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: theme.spacing(1) }, children: [_jsx(SettingsSectionTitle, { children: "API Keys" }), _jsx(Tooltip, { title: "API keys are stored locally in your browser's memory for the duration of your session only\n and are only sent to the Neuro SAN service for use with the associated LLM provider when you use\n this application to interact with networks.\n Your keys are never sent to any other servers or services and are not stored on our servers.\n When you close this tab or your browser, your keys will be permanently cleared from memory and\n you will need to enter them again to use services that require them.", children: _jsxs(Typography, { sx: {
|
|
337
|
+
alignSelf: "flex-start",
|
|
338
|
+
color: "var(--bs-secondary)",
|
|
339
|
+
cursor: "help",
|
|
340
|
+
fontSize: "0.7rem",
|
|
341
|
+
lineHeight: 1,
|
|
342
|
+
mt: 0.5,
|
|
343
|
+
}, variant: "caption", children: [_jsx(Box, { component: "span", sx: { mr: 0.5 }, children: "\u24D8" }), _jsx(Box, { component: "span", sx: {
|
|
344
|
+
borderBottom: "1px dashed",
|
|
345
|
+
pb: 0.25,
|
|
346
|
+
}, children: "How are my keys stored and used?" })] }) })] }), _jsx(SettingsSubsection, { title: "LLM Providers", children: _jsx(Box, { sx: { display: "flex", flexDirection: "column", alignItems: "center", gap: 1.5 }, children: apiKeyConfigs.map(({ checkmark, vendor, idSuffix, logo, onTest, placeholder }) => (_jsx(SettingsRow, { checkmark: checkmark, label: "", tooltip: `API key for ${vendor}.`, children: _jsx(ApiKeyInput, { forgetKey: () => persistKey(vendor, "", checkmark, 0), id: `${id}-${idSuffix}`, logo: logo, onSave: (key) => persistKey(vendor, key, checkmark, Date.now()), onTest: onTest, persistedValue: getApiKey(apiKeys, vendor), placeholder: placeholder, vendor: vendor }) }, `${id}-${idSuffix}`))) }) })] }));
|
|
330
347
|
const getBehaviorSection = () => (_jsxs(Section, { children: [_jsx(SettingsSectionTitle, { children: "Behavior" }), _jsx(SettingsSubsection, { title: "Zen mode", children: _jsx(SettingsRow, { label: 'Enable "Zen" mode:', checkmark: enableZenModeCheckmark, tooltip: "Hides most of the UI during agent network animations providing a more immersive " +
|
|
331
348
|
"experience.", children: _jsx(Checkbox, { checked: enableZenMode, "data-testid": "zen-mode-checkbox", onChange: (_, checked) => {
|
|
332
349
|
updateSettings({ behavior: { enableZenMode: checked } });
|
|
@@ -345,7 +362,6 @@ export const SettingsDialog = ({ id, isOpen, logoServiceToken, onClose }) => {
|
|
|
345
362
|
nativeNamesCheckmark.trigger();
|
|
346
363
|
}
|
|
347
364
|
}, size: "small", value: useNativeNames ? "native" : "beautified", children: [_jsx(ToggleButton, { value: "native", children: "Native" }), _jsx(ToggleButton, { value: "beautified", children: "Beautified" })] }), _jsx(FormLabel, { children: "Preview: " }), _jsx(FormLabel, { sx: {
|
|
348
|
-
marginBottom: 0,
|
|
349
365
|
border: "1px solid",
|
|
350
366
|
borderRadius: 1,
|
|
351
367
|
backgroundColor: "background.paper",
|
|
@@ -456,7 +472,7 @@ export const SettingsDialog = ({ id, isOpen, logoServiceToken, onClose }) => {
|
|
|
456
472
|
},
|
|
457
473
|
}), [paletteMode]);
|
|
458
474
|
return (
|
|
459
|
-
// Always use default theme for settings dialog so user can always see to reset. It's possible that with
|
|
475
|
+
// Always use the default theme for settings dialog so user can always see to reset. It's possible that with
|
|
460
476
|
// certain custom themes the dialog would be unreadable.
|
|
461
477
|
_jsxs(ThemeProvider, { theme: settingsTheme, children: [resetToDefaultSettingsOpen ? getConfirmationModal() : null, _jsxs(MUIDialog, { id: id, title: _jsx(Box, { sx: { fontSize: "1.5rem" }, children: "Settings" }), isOpen: isOpen, onClose: onClose, paperProps: {
|
|
462
478
|
minWidth: "50%",
|
|
@@ -2,11 +2,19 @@ import { AgentNetworkDefinitionEntry } from "../../components/MultiAgentAccelera
|
|
|
2
2
|
import { AgentInfo, ChatContext, ChatResponse, ConnectivityResponse, FunctionResponse } from "../../generated/neuro-san/NeuroSanClient.js";
|
|
3
3
|
import { StreamingUnit } from "../llm/LlmChat.js";
|
|
4
4
|
import { BrandingSuggestions } from "../Types/Branding.js";
|
|
5
|
+
export interface HealthCheckResponse {
|
|
6
|
+
readonly service?: string;
|
|
7
|
+
readonly status?: string;
|
|
8
|
+
readonly versions?: {
|
|
9
|
+
readonly "neuro-san-studio"?: string;
|
|
10
|
+
readonly "neuro-san"?: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
5
13
|
export interface TestConnectionResult {
|
|
14
|
+
readonly healthCheckResponse?: HealthCheckResponse;
|
|
6
15
|
readonly httpStatus?: number;
|
|
7
|
-
readonly
|
|
16
|
+
readonly statusText?: string;
|
|
8
17
|
readonly success: boolean;
|
|
9
|
-
readonly version?: string;
|
|
10
18
|
}
|
|
11
19
|
/**
|
|
12
20
|
* Test connection for a neuro-san server.
|
|
@@ -64,8 +72,8 @@ export declare const getConnectivity: (url: string, network: string, userId: str
|
|
|
64
72
|
*/
|
|
65
73
|
export declare const getAgentFunction: (url: string, agent: string, userId: string) => Promise<FunctionResponse>;
|
|
66
74
|
/**
|
|
67
|
-
* Streams the Agent Network Designer endpoint with an
|
|
68
|
-
* Calls `onChunk` for each line received; callers are
|
|
69
|
-
* reservations / networks out of each chunk.
|
|
75
|
+
* Streams the Agent Network Designer endpoint with an agent definition, either updating an
|
|
76
|
+
* existing network or adding a fresh one. Calls `onChunk` for each line received; callers are
|
|
77
|
+
* responsible for parsing reservations / networks out of each chunk.
|
|
70
78
|
*/
|
|
71
|
-
export declare const
|
|
79
|
+
export declare const sendNetworkDesignerRequest: (url: string, signal: AbortSignal, agentName: string, updated: AgentNetworkDefinitionEntry[], agentNetworkName: string | undefined, currentUser: string, onChunk: (chunk: string) => void) => Promise<void>;
|
|
@@ -50,23 +50,27 @@ export const testConnection = async (url) => {
|
|
|
50
50
|
const response = await fetch(url, { signal: controller.signal });
|
|
51
51
|
if (!response.ok) {
|
|
52
52
|
return {
|
|
53
|
-
success: false,
|
|
54
53
|
httpStatus: response.status,
|
|
55
|
-
|
|
54
|
+
statusText: response.statusText,
|
|
55
|
+
success: false,
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
const jsonResponse = await response.json();
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
const statusText = jsonResponse?.status;
|
|
60
|
+
const success = statusText === "ok";
|
|
61
|
+
return {
|
|
62
|
+
healthCheckResponse: jsonResponse,
|
|
63
|
+
httpStatus: response.status,
|
|
64
|
+
statusText,
|
|
65
|
+
success,
|
|
66
|
+
};
|
|
66
67
|
}
|
|
67
68
|
catch (error) {
|
|
68
69
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
69
|
-
return {
|
|
70
|
+
return {
|
|
71
|
+
statusText: errorMessage,
|
|
72
|
+
success: false,
|
|
73
|
+
};
|
|
70
74
|
}
|
|
71
75
|
finally {
|
|
72
76
|
clearTimeout(timeout);
|
|
@@ -180,11 +184,11 @@ export const getAgentFunction = async (url, agent, userId) => {
|
|
|
180
184
|
return response.json();
|
|
181
185
|
};
|
|
182
186
|
/**
|
|
183
|
-
* Streams the Agent Network Designer endpoint with an
|
|
184
|
-
* Calls `onChunk` for each line received; callers are
|
|
185
|
-
* reservations / networks out of each chunk.
|
|
187
|
+
* Streams the Agent Network Designer endpoint with an agent definition, either updating an
|
|
188
|
+
* existing network or adding a fresh one. Calls `onChunk` for each line received; callers are
|
|
189
|
+
* responsible for parsing reservations / networks out of each chunk.
|
|
186
190
|
*/
|
|
187
|
-
export const
|
|
191
|
+
export const sendNetworkDesignerRequest = async (url, signal, agentName, updated, agentNetworkName, currentUser, onChunk) => {
|
|
188
192
|
await sendChatQuery(url, signal,
|
|
189
193
|
// Shouldn't have to pass a user message, but API behaves differently without it
|
|
190
194
|
`Update instructions for agent "${agentName}"`, AGENT_NETWORK_DESIGNER_ID, onChunk, null, {
|
package/dist/index.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export * from "./components/Common/notification.js";
|
|
|
23
23
|
export * from "./components/ErrorPage/ErrorBoundary.js";
|
|
24
24
|
export * from "./components/MultiAgentAccelerator/AgentConversations.js";
|
|
25
25
|
export * from "./components/MultiAgentAccelerator/AgentCounts.js";
|
|
26
|
-
export * from "./components/MultiAgentAccelerator/AgentFlow.js";
|
|
26
|
+
export * from "./components/MultiAgentAccelerator/AgentFlow/AgentFlow.js";
|
|
27
27
|
export * from "./components/MultiAgentAccelerator/MultiAgentAccelerator.js";
|
|
28
28
|
export * from "./components/MultiAgentAccelerator/Sidebar/Sidebar.js";
|
|
29
29
|
export * from "./components/MultiAgentAccelerator/TemporaryNetworks.js";
|
package/dist/index.js
CHANGED
|
@@ -38,7 +38,7 @@ export * from "./components/Common/notification.js";
|
|
|
38
38
|
export * from "./components/ErrorPage/ErrorBoundary.js";
|
|
39
39
|
export * from "./components/MultiAgentAccelerator/AgentConversations.js";
|
|
40
40
|
export * from "./components/MultiAgentAccelerator/AgentCounts.js";
|
|
41
|
-
export * from "./components/MultiAgentAccelerator/AgentFlow.js";
|
|
41
|
+
export * from "./components/MultiAgentAccelerator/AgentFlow/AgentFlow.js";
|
|
42
42
|
export * from "./components/MultiAgentAccelerator/MultiAgentAccelerator.js";
|
|
43
43
|
export * from "./components/MultiAgentAccelerator/Sidebar/Sidebar.js";
|
|
44
44
|
export * from "./components/MultiAgentAccelerator/TemporaryNetworks.js";
|
package/dist/state/Settings.d.ts
CHANGED
|
@@ -11,6 +11,13 @@ type DeepPartial<T> = {
|
|
|
11
11
|
};
|
|
12
12
|
export type LLMProvider = "OpenAI" | "Anthropic";
|
|
13
13
|
export type LogoSource = "none" | "generic" | "auto";
|
|
14
|
+
export type ByokKeyField = (typeof LLM_PROVIDER_API_KEY_FIELD)[LLMProvider];
|
|
15
|
+
interface ApiKeyEntry {
|
|
16
|
+
readonly value: string;
|
|
17
|
+
readonly expiresAt: number;
|
|
18
|
+
}
|
|
19
|
+
type ApiKeys = Partial<Record<LLMProvider, ApiKeyEntry>>;
|
|
20
|
+
export type PaletteKey = keyof typeof PALETTES | "brand";
|
|
14
21
|
/**
|
|
15
22
|
* User preference settings
|
|
16
23
|
*/
|
|
@@ -35,7 +42,7 @@ interface Settings {
|
|
|
35
42
|
readonly behavior: {
|
|
36
43
|
readonly enableZenMode: boolean;
|
|
37
44
|
};
|
|
38
|
-
readonly apiKeys:
|
|
45
|
+
readonly apiKeys: ApiKeys;
|
|
39
46
|
readonly externalServices: {
|
|
40
47
|
neuroSanUrl: string | null;
|
|
41
48
|
};
|
|
@@ -48,25 +55,95 @@ interface SettingsStore {
|
|
|
48
55
|
readonly updateSettings: (updates: DeepPartial<Settings>) => void;
|
|
49
56
|
readonly resetSettings: () => void;
|
|
50
57
|
}
|
|
58
|
+
export declare const LLM_PROVIDER_API_KEY_FIELD: {
|
|
59
|
+
readonly OpenAI: "openai_api_key";
|
|
60
|
+
readonly Anthropic: "anthropic_api_key";
|
|
61
|
+
};
|
|
51
62
|
/**
|
|
52
63
|
* Default settings, used on first load and on reset
|
|
53
64
|
*/
|
|
54
65
|
export declare const DEFAULT_SETTINGS: Settings;
|
|
66
|
+
export declare const APP_SETTINGS_STORAGE_KEY = "app-settings";
|
|
67
|
+
export declare const SESSION_API_KEYS_STORAGE_KEY = "app-settings-api-keys";
|
|
68
|
+
export declare const API_KEYS_TTL_MS: number;
|
|
69
|
+
/**
|
|
70
|
+
* Returns the API key for the given provider if it exists and is not expired, otherwise returns undefined.
|
|
71
|
+
* This helper should be used to retrieve API keys from the settings store, rather than accessing the store directly,
|
|
72
|
+
* to ensure that expired keys are not returned.
|
|
73
|
+
* @param apiKeys Set of API keys stored in the settings store
|
|
74
|
+
* @param provider The LLM provider for which to retrieve the API key
|
|
75
|
+
*/
|
|
76
|
+
export declare const getApiKey: (apiKeys: ApiKeys, provider: LLMProvider) => string;
|
|
55
77
|
/**
|
|
56
78
|
* The hook that lets apps use the store
|
|
57
79
|
*/
|
|
58
80
|
export declare const useSettingsStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<SettingsStore>, "persist"> & {
|
|
59
81
|
persist: {
|
|
60
|
-
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<SettingsStore,
|
|
82
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<SettingsStore, {
|
|
83
|
+
settings: {
|
|
84
|
+
appearance: {
|
|
85
|
+
readonly agentIconColor: string;
|
|
86
|
+
readonly agentNodeColor: string;
|
|
87
|
+
readonly autoAgentIconColor: boolean;
|
|
88
|
+
readonly plasmaColor: string;
|
|
89
|
+
readonly rangePalette: PaletteKey;
|
|
90
|
+
readonly useNativeNames: boolean;
|
|
91
|
+
};
|
|
92
|
+
branding: {
|
|
93
|
+
readonly customer: string | null;
|
|
94
|
+
readonly primary: string | null;
|
|
95
|
+
readonly secondary: string | null;
|
|
96
|
+
readonly background: string | null;
|
|
97
|
+
readonly rangePalette: string[] | null;
|
|
98
|
+
readonly iconSuggestion: string | null;
|
|
99
|
+
readonly logoSource: LogoSource;
|
|
100
|
+
};
|
|
101
|
+
behavior: {
|
|
102
|
+
readonly enableZenMode: boolean;
|
|
103
|
+
};
|
|
104
|
+
externalServices: {
|
|
105
|
+
neuroSanUrl: string | null;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
updateSettings: (updates: DeepPartial<Settings>) => void;
|
|
109
|
+
resetSettings: () => void;
|
|
110
|
+
}>>) => void;
|
|
61
111
|
clearStorage: () => void;
|
|
62
112
|
rehydrate: () => Promise<void> | void;
|
|
63
113
|
hasHydrated: () => boolean;
|
|
64
114
|
onHydrate: (fn: (state: SettingsStore) => void) => () => void;
|
|
65
115
|
onFinishHydration: (fn: (state: SettingsStore) => void) => () => void;
|
|
66
|
-
getOptions: () => Partial<import("zustand/middleware").PersistOptions<SettingsStore,
|
|
116
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<SettingsStore, {
|
|
117
|
+
settings: {
|
|
118
|
+
appearance: {
|
|
119
|
+
readonly agentIconColor: string;
|
|
120
|
+
readonly agentNodeColor: string;
|
|
121
|
+
readonly autoAgentIconColor: boolean;
|
|
122
|
+
readonly plasmaColor: string;
|
|
123
|
+
readonly rangePalette: PaletteKey;
|
|
124
|
+
readonly useNativeNames: boolean;
|
|
125
|
+
};
|
|
126
|
+
branding: {
|
|
127
|
+
readonly customer: string | null;
|
|
128
|
+
readonly primary: string | null;
|
|
129
|
+
readonly secondary: string | null;
|
|
130
|
+
readonly background: string | null;
|
|
131
|
+
readonly rangePalette: string[] | null;
|
|
132
|
+
readonly iconSuggestion: string | null;
|
|
133
|
+
readonly logoSource: LogoSource;
|
|
134
|
+
};
|
|
135
|
+
behavior: {
|
|
136
|
+
readonly enableZenMode: boolean;
|
|
137
|
+
};
|
|
138
|
+
externalServices: {
|
|
139
|
+
neuroSanUrl: string | null;
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
updateSettings: (updates: DeepPartial<Settings>) => void;
|
|
143
|
+
resetSettings: () => void;
|
|
144
|
+
}>>;
|
|
67
145
|
};
|
|
68
146
|
}>;
|
|
69
|
-
export type PaletteKey = keyof typeof PALETTES | "brand";
|
|
70
147
|
/**
|
|
71
148
|
* Custom hook to get the current color palette based on user settings.
|
|
72
149
|
* If the user has selected custom branding, it will return the palette for that.
|