@gooddata/sdk-ui-gen-ai 11.41.0-alpha.5 → 11.42.0-alpha.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/esm/components/GenAIChatAgentDropdown.d.ts.map +1 -1
- package/esm/components/GenAIChatAgentDropdown.js +12 -11
- package/esm/components/Input.d.ts.map +1 -1
- package/esm/components/Input.js +6 -4
- package/esm/components/utils/agentSelection.d.ts +2 -1
- package/esm/components/utils/agentSelection.d.ts.map +1 -1
- package/esm/components/utils/agentSelection.js +6 -1
- package/esm/store/messages/messagesSlice.d.ts.map +1 -1
- package/esm/store/messages/messagesSlice.js +10 -1
- package/esm/store/sideEffects/index.d.ts.map +1 -1
- package/esm/store/sideEffects/index.js +5 -0
- package/esm/store/sideEffects/onChatOpenSync.d.ts +44 -0
- package/esm/store/sideEffects/onChatOpenSync.d.ts.map +1 -0
- package/esm/store/sideEffects/onChatOpenSync.js +141 -0
- package/package.json +20 -20
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GenAIChatAgentDropdown.d.ts","sourceRoot":"","sources":["../../src/components/GenAIChatAgentDropdown.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAiB3E,MAAM,MAAM,2BAA2B,GAAG;IACtC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,aAAa,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACzC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CACjG,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,EACnC,MAAM,EACN,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,SAAS,EACT,aAAa,EAChB,EAAE,2BAA2B,
|
|
1
|
+
{"version":3,"file":"GenAIChatAgentDropdown.d.ts","sourceRoot":"","sources":["../../src/components/GenAIChatAgentDropdown.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAiB3E,MAAM,MAAM,2BAA2B,GAAG;IACtC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,aAAa,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACzC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CACjG,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,EACnC,MAAM,EACN,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,UAAU,EACV,SAAS,EACT,aAAa,EAChB,EAAE,2BAA2B,2CAqH7B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// (C) 2026 GoodData Corporation
|
|
3
3
|
import { useEffect, useMemo } from "react";
|
|
4
4
|
import cx from "classnames";
|
|
@@ -34,7 +34,7 @@ export function GenAIChatAgentDropdown({ agents, conversations, conversationAgen
|
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
36
|
if (agents.length) {
|
|
37
|
-
onSelectAgent(isSelectedAgentAvailable ? selectedAgentId : selectDefaultAgentId(agents, conversations)
|
|
37
|
+
onSelectAgent(isSelectedAgentAvailable ? selectedAgentId : selectDefaultAgentId(agents, conversations));
|
|
38
38
|
}
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
@@ -56,18 +56,19 @@ export function GenAIChatAgentDropdown({ agents, conversations, conversationAgen
|
|
|
56
56
|
isDisabled: false,
|
|
57
57
|
data: agent,
|
|
58
58
|
tooltip: agent.description || undefined,
|
|
59
|
+
ariaAttributes: agent.description
|
|
60
|
+
? { "aria-label": `${agent.title}. ${agent.description}` }
|
|
61
|
+
: undefined,
|
|
59
62
|
iconRight: agent.description ? (_jsx(UiIcon, { type: "question", size: 12, color: isSelected ? "complementary-7" : "complementary-5", accessibilityConfig: { ariaHidden: true } })) : undefined,
|
|
60
63
|
};
|
|
61
64
|
}), [agents, effectiveSelectedAgentId]);
|
|
62
|
-
return (
|
|
63
|
-
"gd-gen-ai-chat__input__agent-dropdown
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
closeDropdown();
|
|
70
|
-
} })) }));
|
|
65
|
+
return (_jsxs(_Fragment, { children: [
|
|
66
|
+
_jsx("span", { className: "sr-only", "aria-live": "polite", "aria-atomic": "true", children: isLoading ? loadingLabel : "" }), _jsx(Dropdown, { className: cx("gd-gen-ai-chat__input__agent-dropdown", {
|
|
67
|
+
"gd-gen-ai-chat__input__agent-dropdown--loading": isLoading,
|
|
68
|
+
}), alignPoints: [{ align: "tr br", offset: { x: 0, y: 0 } }], closeOnEscape: true, fullscreenOnMobile: false, autofocusOnOpen: true, accessibilityConfig: {}, renderButton: ({ isOpen, toggleDropdown, accessibilityConfig }) => (_jsx(UiButton, { label: isLoading ? loadingLabel : (selectedAgent?.title ?? agentLabel), variant: "dropdownInline", size: "small", iconAfter: isLoading ? undefined : isOpen ? "navigateUp" : "navigateDown", isDisabled: isLoading || isDisabled || !agents.length, onClick: toggleDropdown, dataTestId: "agent_dropdown_button", accessibilityConfig: accessibilityConfig })), renderBody: ({ closeDropdown, ariaAttributes }) => (_jsx(UiMenu, { dataTestId: "agent_dropdown_menu", items: items, size: "small", minWidth: 160, maxWidth: 220, containerTopPadding: "small", containerBottomPadding: "small", MenuHeader: AgentMenuHeader, ariaAttributes: ariaAttributes, onSelect: (item) => {
|
|
69
|
+
onSelectAgent(item.data.id, { showChangeEvent: true });
|
|
70
|
+
closeDropdown();
|
|
71
|
+
} })) })] }));
|
|
71
72
|
}
|
|
72
73
|
function AgentMenuHeader() {
|
|
73
74
|
const intl = useIntl();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../src/components/Input.tsx"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,EAAE,EACP,KAAK,SAAS,EASjB,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../../src/components/Input.tsx"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,EAAE,EACP,KAAK,SAAS,EASjB,MAAM,OAAO,CAAC;AAyCf,MAAM,MAAM,aAAa,GAAG;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;CACzC,CAAC;AAiYF,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC,aAAa,CAAgE,CAAC"}
|
package/esm/components/Input.js
CHANGED
|
@@ -7,7 +7,7 @@ import { connect } from "react-redux";
|
|
|
7
7
|
import { SyntaxHighlightingInput, UiIconButton, UiTooltip } from "@gooddata/sdk-ui-kit";
|
|
8
8
|
import { makeTextContents, makeUserItem, makeUserMessage, } from "../model.js";
|
|
9
9
|
import { agentSwitchingActiveSelector, agentSwitchingEnabledSelector, } from "../store/chatWindow/chatWindowSelectors.js";
|
|
10
|
-
import { agentsSelector, asyncProcessSelector, conversationMessagesSelector, conversationSelector, conversationsSelector, messagesSelector, selectedAgentIdSelector, } from "../store/messages/messagesSelectors.js";
|
|
10
|
+
import { agentsSelector, asyncProcessSelector, conversationMessagesSelector, conversationSelector, conversationsLoadedSelector, conversationsSelector, messagesSelector, selectedAgentIdSelector, } from "../store/messages/messagesSelectors.js";
|
|
11
11
|
import { newMessageAction, setSelectedAgentAction } from "../store/messages/messagesSlice.js";
|
|
12
12
|
import { collectReferences } from "./completion/references.js";
|
|
13
13
|
import { useCompletion } from "./completion/useCompletion.js";
|
|
@@ -35,7 +35,7 @@ const msgs = defineMessages({
|
|
|
35
35
|
});
|
|
36
36
|
const isMac = typeof navigator !== "undefined" &&
|
|
37
37
|
(navigator.platform.toUpperCase().indexOf("MAC") >= 0 || navigator.userAgent.includes("Macintosh"));
|
|
38
|
-
function InputComponent({ isBusy, isEvaluating, newMessage, autofocus = false, canManage, canAnalyze, targetRef, messages, conversation, conversations, items, agents, agentSwitchingEnabled, agentSwitchingActive, loading, selectedAgentId, setSelectedAgent, }) {
|
|
38
|
+
function InputComponent({ isBusy, isEvaluating, newMessage, autofocus = false, canManage, canAnalyze, targetRef, messages, conversation, conversations, conversationsLoaded, items, agents, agentSwitchingEnabled, agentSwitchingActive, loading, selectedAgentId, setSelectedAgent, }) {
|
|
39
39
|
const intl = useIntl();
|
|
40
40
|
const { isBigScreen, isSmallScreen, isFullscreen } = useFullscreenCheck();
|
|
41
41
|
const isLoading = loading === "loading" || loading === "clearing";
|
|
@@ -47,6 +47,7 @@ function InputComponent({ isBusy, isEvaluating, newMessage, autofocus = false, c
|
|
|
47
47
|
const { availableAgents, hasNoAgents, isSelectionLoading } = getAgentSelectionStatus({
|
|
48
48
|
agentSwitchingActive,
|
|
49
49
|
assistantLoading: isAssistantLoading,
|
|
50
|
+
conversationsLoaded,
|
|
50
51
|
agents,
|
|
51
52
|
selectedAgentId,
|
|
52
53
|
});
|
|
@@ -160,7 +161,7 @@ function InputComponent({ isBusy, isEvaluating, newMessage, autofocus = false, c
|
|
|
160
161
|
"gd-gen-ai-chat__input__actions": agentSwitchingEnabled,
|
|
161
162
|
"gd-gen-ai-chat__input__send_button": !agentSwitchingEnabled,
|
|
162
163
|
"gd-gen-ai-chat__input__send_button--disabled": !agentSwitchingEnabled && buttonDisabled,
|
|
163
|
-
}), onMouseDown: agentSwitchingEnabled ? handleActionsMouseDown : undefined, children: agentSwitchingActive && hasNoAgents ? (_jsx("span", { className: "gd-gen-ai-chat__input__no-agent", "data-testid": "no_agent_available", children: noAgentAvailableLabel })) : agentSwitchingEnabled ? (_jsxs(_Fragment, { children: [agentSwitchingActive ? (_jsx(GenAIChatAgentDropdown, { agents: availableAgents, conversations: conversations, conversationAgentId: conversation?.agentId, selectedAgentId: selectedAgentId, isDisabled: agentDropdownDisabled, isLoading: isSelectionLoading, onSelectAgent: handleSelectAgent })) : null, _jsx(UiTooltip, { triggerBy: ["focus", "hover"], arrowPlacement: "bottom", anchor: _jsx(UiIconButton, { icon: "arrowUp", variant: "primary", size: "small", dataTestId: "send_message", isDisabled: buttonDisabled, onClick: buttonDisabled ? undefined : handleSubmit, accessibilityConfig: {
|
|
164
|
+
}), onMouseDown: agentSwitchingEnabled ? handleActionsMouseDown : undefined, children: agentSwitchingActive && hasNoAgents ? (_jsx("span", { className: "gd-gen-ai-chat__input__no-agent", "data-testid": "no_agent_available", role: "status", "aria-live": "polite", "aria-atomic": "true", children: noAgentAvailableLabel })) : agentSwitchingEnabled ? (_jsxs(_Fragment, { children: [agentSwitchingActive ? (_jsx(GenAIChatAgentDropdown, { agents: availableAgents, conversations: conversations, conversationAgentId: conversation?.agentId, selectedAgentId: selectedAgentId, isDisabled: agentDropdownDisabled, isLoading: isSelectionLoading, onSelectAgent: handleSelectAgent })) : null, _jsx(UiTooltip, { triggerBy: ["focus", "hover"], arrowPlacement: "bottom", anchor: _jsx(UiIconButton, { icon: "arrowUp", variant: "primary", size: "small", dataTestId: "send_message", isDisabled: buttonDisabled, onClick: buttonDisabled ? undefined : handleSubmit, accessibilityConfig: {
|
|
164
165
|
ariaLabel: sendLabel,
|
|
165
166
|
} }), content: sendLabel })
|
|
166
167
|
] })) : (_jsx(UiTooltip, { triggerBy: ["focus", "hover"], arrowPlacement: "bottom", anchor: _jsx(UiIconButton, { icon: "send", variant: "tertiary", size: "medium", dataTestId: "send_message", isDisabled: buttonDisabled, onClick: buttonDisabled ? undefined : handleSubmit, accessibilityConfig: {
|
|
@@ -170,7 +171,7 @@ function InputComponent({ isBusy, isEvaluating, newMessage, autofocus = false, c
|
|
|
170
171
|
] }) }));
|
|
171
172
|
}
|
|
172
173
|
function HintText({ where, focused }) {
|
|
173
|
-
return (_jsx("div", { className: cx("gd-gen-ai-chat__input__info", {
|
|
174
|
+
return (_jsx("div", { "aria-hidden": !focused, className: cx("gd-gen-ai-chat__input__info", {
|
|
174
175
|
hidden: !focused,
|
|
175
176
|
top: where === "top",
|
|
176
177
|
bottom: where === "bottom",
|
|
@@ -185,6 +186,7 @@ const mapStateToProps = (state) => {
|
|
|
185
186
|
return {
|
|
186
187
|
conversation: conversationSelector(state),
|
|
187
188
|
conversations: conversationsSelector(state),
|
|
189
|
+
conversationsLoaded: conversationsLoadedSelector(state),
|
|
188
190
|
items: conversationMessagesSelector(state),
|
|
189
191
|
messages: messagesSelector(state),
|
|
190
192
|
loading: asyncState,
|
|
@@ -9,9 +9,10 @@ export declare function getEffectiveSelectedAgentId({ agents, conversationAgentI
|
|
|
9
9
|
conversationAgentId?: string;
|
|
10
10
|
selectedAgentId?: string;
|
|
11
11
|
}): string | undefined;
|
|
12
|
-
export declare function getAgentSelectionStatus({ agentSwitchingActive, assistantLoading, agents, selectedAgentId }: {
|
|
12
|
+
export declare function getAgentSelectionStatus({ agentSwitchingActive, assistantLoading, conversationsLoaded, agents, selectedAgentId }: {
|
|
13
13
|
agentSwitchingActive: boolean;
|
|
14
14
|
assistantLoading?: boolean;
|
|
15
|
+
conversationsLoaded?: boolean;
|
|
15
16
|
agents: GenAIAgent[] | undefined;
|
|
16
17
|
selectedAgentId?: string;
|
|
17
18
|
}): AgentSelectionStatus;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentSelection.d.ts","sourceRoot":"","sources":["../../../src/components/utils/agentSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE9E,MAAM,MAAM,oBAAoB,GAAG;IAC/B,eAAe,EAAE,UAAU,EAAE,CAAC;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,EACxC,MAAM,EACN,mBAAmB,EACnB,eAAe,EAClB,EAAE;IACC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,MAAM,GAAG,SAAS,CAYrB;AAED,wBAAgB,uBAAuB,CAAC,EACpC,oBAAoB,EACpB,gBAAwB,EACxB,MAAM,EACN,eAAe,EAClB,EAAE;IACC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,MAAM,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,oBAAoB,
|
|
1
|
+
{"version":3,"file":"agentSelection.d.ts","sourceRoot":"","sources":["../../../src/components/utils/agentSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE9E,MAAM,MAAM,oBAAoB,GAAG;IAC/B,eAAe,EAAE,UAAU,EAAE,CAAC;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,EACxC,MAAM,EACN,mBAAmB,EACnB,eAAe,EAClB,EAAE;IACC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,MAAM,GAAG,SAAS,CAYrB;AAED,wBAAgB,uBAAuB,CAAC,EACpC,oBAAoB,EACpB,gBAAwB,EACxB,mBAA0B,EAC1B,MAAM,EACN,eAAe,EAClB,EAAE;IACC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,oBAAoB,CAmBvB;AAED,wBAAgB,oBAAoB,CAChC,MAAM,EAAE,UAAU,EAAE,EACpB,aAAa,EAAE,sBAAsB,EAAE,GAAG,SAAS,GACpD,MAAM,GAAG,SAAS,CAmBpB"}
|
|
@@ -9,15 +9,20 @@ export function getEffectiveSelectedAgentId({ agents, conversationAgentId, selec
|
|
|
9
9
|
}
|
|
10
10
|
return undefined;
|
|
11
11
|
}
|
|
12
|
-
export function getAgentSelectionStatus({ agentSwitchingActive, assistantLoading = false, agents, selectedAgentId, }) {
|
|
12
|
+
export function getAgentSelectionStatus({ agentSwitchingActive, assistantLoading = false, conversationsLoaded = true, agents, selectedAgentId, }) {
|
|
13
13
|
const availableAgents = agents ?? [];
|
|
14
14
|
const isSelectedAgentAvailable = !!selectedAgentId && availableAgents.some((a) => a.id === selectedAgentId);
|
|
15
15
|
return {
|
|
16
16
|
availableAgents,
|
|
17
17
|
hasNoAgents: agentSwitchingActive && agents?.length === 0,
|
|
18
|
+
// The conversations list is part of the loading condition so that the dropdown goes
|
|
19
|
+
// through a single loading phase on startup. Without it, the dropdown briefly resolves
|
|
20
|
+
// to a default agent after agents load, then flips back to loading when the current
|
|
21
|
+
// conversation (with a possibly different agent) starts loading.
|
|
18
22
|
isSelectionLoading: agentSwitchingActive &&
|
|
19
23
|
(assistantLoading ||
|
|
20
24
|
agents === undefined ||
|
|
25
|
+
!conversationsLoaded ||
|
|
21
26
|
(availableAgents.length > 0 && !isSelectedAgentAvailable)),
|
|
22
27
|
};
|
|
23
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messagesSlice.d.ts","sourceRoot":"","sources":["../../../src/store/messages/messagesSlice.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,OAAO,EAAe,MAAM,kBAAkB,CAAC;AAEjF,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,KAAK,gCAAgC,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"messagesSlice.d.ts","sourceRoot":"","sources":["../../../src/store/messages/messagesSlice.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// (C) 2024-2026 GoodData Corporation
|
|
2
2
|
import { createSlice } from "@reduxjs/toolkit";
|
|
3
|
+
import { selectDefaultAgentId } from "../../components/utils/agentSelection.js";
|
|
3
4
|
import { isAssistantMessage, isChatConversationLocalItem, isUserMessage, isVisualizationContents, makeAgentChangeItem, makeErrorContent, makeErrorContents, } from "../../model.js";
|
|
4
5
|
import { convertMessageToChatConversation } from "../sideEffects/utils.js";
|
|
5
6
|
import { createEmptyConversation, getConversationData, getConversationLocalId, isConversationWithLocalId, } from "../utils.js";
|
|
@@ -515,7 +516,15 @@ const messagesSlice = createSlice({
|
|
|
515
516
|
revertAgentSwitchAction: (state, { payload, }) => {
|
|
516
517
|
// Only revert the dropdown when the user is still on the failed conversation.
|
|
517
518
|
if (state.currentConversation?.localId === payload.conversationLocalId) {
|
|
518
|
-
|
|
519
|
+
// The conversation itself goes back to its previous agent (possibly none - the
|
|
520
|
+
// server never switched), but the dropdown needs a concrete selection that is
|
|
521
|
+
// actually available, otherwise it would flip into the loading state until a
|
|
522
|
+
// default is re-resolved.
|
|
523
|
+
const isPreviousAgentAvailable = !!payload.previousAgentId &&
|
|
524
|
+
(state.agents ?? []).some((agent) => agent.id === payload.previousAgentId);
|
|
525
|
+
state.selectedAgentId = isPreviousAgentAvailable
|
|
526
|
+
? payload.previousAgentId
|
|
527
|
+
: selectDefaultAgentId(state.agents ?? [], state.conversations);
|
|
519
528
|
state.currentConversation.agentId = payload.previousAgentId;
|
|
520
529
|
}
|
|
521
530
|
state.conversations = state.conversations?.map((conversation) => conversation.localId === payload.conversationLocalId
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/store/sideEffects/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/store/sideEffects/index.ts"],"names":[],"mappings":"AAyCA;;;GAGG;AACH,wBAAiB,QAAQ,4HAyBxB"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// (C) 2024-2026 GoodData Corporation
|
|
2
2
|
import { call, fork, takeEvery, takeLatest } from "redux-saga/effects";
|
|
3
|
+
import { setOpenAction } from "../chatWindow/chatWindowSlice.js";
|
|
3
4
|
import { clearThreadAction, deleteConversationAction, evaluateMessageUpdateAction, loadThreadAction, newMessageAction, pinConversationAction, renameConversationAction, saveVisualisationRenderStatusAction, saveVisualizationAction, saveVisualizationSuccessAction, setSelectedAgentAction, setUserFeedback, setVerboseAction, } from "../messages/messagesSlice.js";
|
|
4
5
|
import { loadAgents } from "./loadAgents.js";
|
|
5
6
|
import { loadCatalogItems } from "./loadCatalogItems.js";
|
|
6
7
|
import { loadColorPalette } from "./loadColorPalette.js";
|
|
7
8
|
import { loadSettings } from "./loadSettings.js";
|
|
8
9
|
import { onAgentSwitch } from "./onAgentSwitch.js";
|
|
10
|
+
import { onChatOpenSync } from "./onChatOpenSync.js";
|
|
9
11
|
import { onConversationDelete } from "./onConversationDelete.js";
|
|
10
12
|
import { onConversationPin } from "./onConversationPin.js";
|
|
11
13
|
import { onConversationRename } from "./onConversationRename.js";
|
|
@@ -26,6 +28,9 @@ import { onVisualizationSuccessSave } from "./onVisualizationSuccessSave.js";
|
|
|
26
28
|
export function* rootSaga() {
|
|
27
29
|
yield takeLatest(loadThreadAction.type, onThreadLoad);
|
|
28
30
|
yield takeLatest(clearThreadAction.type, onThreadClear);
|
|
31
|
+
// Re-sync the active conversation with the backend when the chat is (re)opened so that
|
|
32
|
+
// a conversation started/switched on another host micro-frontend is reflected without reload.
|
|
33
|
+
yield takeLatest(setOpenAction.type, onChatOpenSync);
|
|
29
34
|
yield takeEvery(newMessageAction.type, onUserMessage);
|
|
30
35
|
//messages API
|
|
31
36
|
yield takeEvery(setUserFeedback.type, onUserFeedback);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type PayloadAction } from "@reduxjs/toolkit";
|
|
2
|
+
import { type IChatConversationLocal, type IChatConversationLocalItem } from "../../model.js";
|
|
3
|
+
/**
|
|
4
|
+
* Re-sync the active conversation with the backend whenever the chat window is opened.
|
|
5
|
+
*
|
|
6
|
+
* The host shell hosts several micro-frontends (Catalog, Metric editor, Analytical Designer) and
|
|
7
|
+
* keeps their runtimes alive across client-side navigation. Each runtime owns its own GenAI redux
|
|
8
|
+
* store, which is only populated once on initial mount. As a result, a conversation started or
|
|
9
|
+
* switched to on one micro-frontend was not reflected on another until a full page reload.
|
|
10
|
+
*
|
|
11
|
+
* When the chat is (re)opened we re-fetch the conversation list from the backend and, if another
|
|
12
|
+
* conversation has become the most recently active one, switch to it. We then re-fetch the active
|
|
13
|
+
* thread from the backend and replace the cached messages atomically so that messages created on
|
|
14
|
+
* another micro-frontend show up even when this runtime already had the conversation cached. This
|
|
15
|
+
* keeps the conversation and its messages in sync across host navigation without requiring a manual
|
|
16
|
+
* reload. A flaky/empty backend response never clears what the user is currently looking at.
|
|
17
|
+
*
|
|
18
|
+
* Only runs in agentic conversations mode and only after the initial load finished. A brand-new
|
|
19
|
+
* unsent draft conversation or an in-progress message exchange is never replaced.
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare function onChatOpenSync({ payload: { isOpen } }: PayloadAction<{
|
|
23
|
+
isOpen: boolean;
|
|
24
|
+
}>): Generator<import("redux-saga/effects").CallEffect<IChatConversationLocalItem[]> | import("redux-saga/effects").CallEffect<{
|
|
25
|
+
id: string;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
updatedAt: string;
|
|
28
|
+
title?: string | undefined;
|
|
29
|
+
pinned?: boolean | undefined;
|
|
30
|
+
agentId?: string | undefined;
|
|
31
|
+
localId: string;
|
|
32
|
+
} | undefined> | import("redux-saga/effects").PutEffect<{
|
|
33
|
+
payload: {
|
|
34
|
+
messages?: import("../../model.js").Message[] | undefined;
|
|
35
|
+
items?: IChatConversationLocalItem[] | undefined;
|
|
36
|
+
};
|
|
37
|
+
type: "messages/setMessagesAction";
|
|
38
|
+
}> | import("redux-saga/effects").PutEffect<{
|
|
39
|
+
payload: {
|
|
40
|
+
conversation: IChatConversationLocal;
|
|
41
|
+
};
|
|
42
|
+
type: "messages/setCurrentConversationAction";
|
|
43
|
+
}> | import("redux-saga/effects").SelectEffect, void, never>;
|
|
44
|
+
//# sourceMappingURL=onChatOpenSync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onChatOpenSync.d.ts","sourceRoot":"","sources":["../../../src/store/sideEffects/onChatOpenSync.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUtD,OAAO,EACH,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAElC,MAAM,gBAAgB,CAAC;AAexB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAiB,cAAc,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,CAAC;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;;;;;;;;;;;;;;;;;;;6DAyE1F"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { call, getContext, put, select } from "redux-saga/effects";
|
|
3
|
+
import { makeConversationItem, } from "../../model.js";
|
|
4
|
+
import { settingsSelector } from "../chatWindow/chatWindowSelectors.js";
|
|
5
|
+
import { asyncProcessSelector, conversationSelector, conversationsLoadedSelector, } from "../messages/messagesSelectors.js";
|
|
6
|
+
import { loadConversationsSuccessAction, setCurrentConversationAction, setMessagesAction, } from "../messages/messagesSlice.js";
|
|
7
|
+
import { convertToLocalContent } from "./converters/toLocalContent.js";
|
|
8
|
+
/**
|
|
9
|
+
* Re-sync the active conversation with the backend whenever the chat window is opened.
|
|
10
|
+
*
|
|
11
|
+
* The host shell hosts several micro-frontends (Catalog, Metric editor, Analytical Designer) and
|
|
12
|
+
* keeps their runtimes alive across client-side navigation. Each runtime owns its own GenAI redux
|
|
13
|
+
* store, which is only populated once on initial mount. As a result, a conversation started or
|
|
14
|
+
* switched to on one micro-frontend was not reflected on another until a full page reload.
|
|
15
|
+
*
|
|
16
|
+
* When the chat is (re)opened we re-fetch the conversation list from the backend and, if another
|
|
17
|
+
* conversation has become the most recently active one, switch to it. We then re-fetch the active
|
|
18
|
+
* thread from the backend and replace the cached messages atomically so that messages created on
|
|
19
|
+
* another micro-frontend show up even when this runtime already had the conversation cached. This
|
|
20
|
+
* keeps the conversation and its messages in sync across host navigation without requiring a manual
|
|
21
|
+
* reload. A flaky/empty backend response never clears what the user is currently looking at.
|
|
22
|
+
*
|
|
23
|
+
* Only runs in agentic conversations mode and only after the initial load finished. A brand-new
|
|
24
|
+
* unsent draft conversation or an in-progress message exchange is never replaced.
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export function* onChatOpenSync({ payload: { isOpen } }) {
|
|
28
|
+
// Only act when the chat is being opened.
|
|
29
|
+
if (!isOpen) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const settings = yield select(settingsSelector);
|
|
33
|
+
// Only the agentic conversations flow keeps a list of conversations on the backend.
|
|
34
|
+
if (!settings?.enableAiAgenticConversations) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// The very first open is handled by the regular thread loading; only re-sync afterwards.
|
|
38
|
+
const conversationsLoaded = yield select(conversationsLoadedSelector);
|
|
39
|
+
if (!conversationsLoaded) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Do not interrupt a genuine in-flight exchange. We deliberately only bail on "evaluating"
|
|
43
|
+
// (a user message is being processed) and "clearing" (the user is resetting the thread).
|
|
44
|
+
// "loading"/"restoring" merely indicate the initial thread load that useThreadLoading kicks
|
|
45
|
+
// off on (re)open - that load happens *before* setOpenAction in the same render commit, so
|
|
46
|
+
// treating it as "in progress" here would suppress every legitimate open-sync. Re-syncing in
|
|
47
|
+
// that state is safe: we fetch the thread ourselves and replace the messages atomically once it
|
|
48
|
+
// resolves, which supersedes whatever the concurrent initial load produces.
|
|
49
|
+
const asyncProcess = yield select(asyncProcessSelector);
|
|
50
|
+
if (asyncProcess === "evaluating" || asyncProcess === "clearing") {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const current = yield select(conversationSelector);
|
|
54
|
+
// Keep a brand-new, not-yet-persisted draft conversation as-is.
|
|
55
|
+
if (current && !current.id) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const latest = yield call(fetchLatestConversation);
|
|
60
|
+
// Empty (or transient) backend result - most likely a flaky list fetch. Keep the current UI
|
|
61
|
+
// (list + thread) untouched rather than half-clearing it. fetchLatestConversation already
|
|
62
|
+
// refrains from clobbering the stored list in this case, so there is nothing to reconcile.
|
|
63
|
+
if (!latest) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// Fetch the latest thread from the backend FIRST, then commit the result atomically.
|
|
67
|
+
//
|
|
68
|
+
// We deliberately do this before touching the store. The previous implementation cleared the
|
|
69
|
+
// cached messages and dispatched loadThreadAction to reload them, but that had two problems:
|
|
70
|
+
// - a failed reload left the user staring at an empty thread (the cache was already wiped),
|
|
71
|
+
// - it relied on switching the conversation first, which flips loaded=false and lets
|
|
72
|
+
// useThreadLoading kick off its own concurrent onThreadLoad - an append-based load that
|
|
73
|
+
// could duplicate history against ours.
|
|
74
|
+
//
|
|
75
|
+
// Fetching first and only then dispatching means: on failure the catch below leaves the
|
|
76
|
+
// previously loaded messages untouched, and on success we apply the switch and the messages
|
|
77
|
+
// back-to-back without yielding, so loaded never transiently flips to false and no concurrent
|
|
78
|
+
// load is triggered. The item list is built purely from the backend response (we do NOT append
|
|
79
|
+
// to existing cached items), so re-creating items with fresh localIds cannot duplicate history.
|
|
80
|
+
const items = yield call(fetchConversationItems, latest.id);
|
|
81
|
+
// Switch to the latest conversation if it differs from the current one. setMessagesAction
|
|
82
|
+
// writes into whatever currentConversation points at, so the switch must come first - and
|
|
83
|
+
// both puts are dispatched synchronously (no yield between them) so the UI never observes the
|
|
84
|
+
// intermediate empty/unloaded state.
|
|
85
|
+
if (latest.id !== current?.id) {
|
|
86
|
+
yield put(setCurrentConversationAction({ conversation: latest }));
|
|
87
|
+
}
|
|
88
|
+
yield put(setMessagesAction({ items }));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Fail silently - keep showing whatever is currently loaded.
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Re-fetch the conversation list and return the most recently updated conversation.
|
|
96
|
+
*
|
|
97
|
+
* Only refreshes the stored list when the backend actually returns conversations. An empty result
|
|
98
|
+
* is treated as transient and left to the caller, so we never clear the history panel while the
|
|
99
|
+
* chat still shows a thread (which would be an inconsistent half-cleared state).
|
|
100
|
+
* @internal
|
|
101
|
+
*/
|
|
102
|
+
function* fetchLatestConversation() {
|
|
103
|
+
const backend = yield getContext("backend");
|
|
104
|
+
const workspace = yield getContext("workspace");
|
|
105
|
+
const isPreview = yield getContext("isPreview");
|
|
106
|
+
const api = backend.workspace(workspace).genAI().getChatConversations({ isPreview });
|
|
107
|
+
const query = api.getConversationItemsQuery().withSize(100).withPage(0);
|
|
108
|
+
const getConversations = query.query.bind(query);
|
|
109
|
+
const results = yield call(getConversations);
|
|
110
|
+
const conversations = results.items.map((item) => ({ ...item, localId: item.id }));
|
|
111
|
+
// Nothing on the backend - do not clobber the stored list; keep whatever is currently shown.
|
|
112
|
+
if (conversations.length === 0) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
// Refresh the stored list so the history panel reflects the latest state too.
|
|
116
|
+
yield put(loadConversationsSuccessAction({ conversations }));
|
|
117
|
+
return conversations
|
|
118
|
+
.slice()
|
|
119
|
+
.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime())[0];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Fetch the thread history for the given conversation and convert it to local items.
|
|
123
|
+
*
|
|
124
|
+
* Mirrors how onThreadLoad's fetchCurrentConversation builds items from the backend response, but
|
|
125
|
+
* intentionally returns ONLY the backend items (no merge/append with cached items) so the caller can
|
|
126
|
+
* replace the cached history wholesale without duplicating it.
|
|
127
|
+
* @internal
|
|
128
|
+
*/
|
|
129
|
+
function* fetchConversationItems(conversationId) {
|
|
130
|
+
const backend = yield getContext("backend");
|
|
131
|
+
const workspace = yield getContext("workspace");
|
|
132
|
+
const isPreview = yield getContext("isPreview");
|
|
133
|
+
const api = backend.workspace(workspace).genAI().getChatConversations({ isPreview });
|
|
134
|
+
const preparedThread = api.getConversationThread(conversationId);
|
|
135
|
+
const loadHistory = preparedThread.loadHistory.bind(preparedThread);
|
|
136
|
+
const results = yield call(loadHistory);
|
|
137
|
+
return results.map((item) => makeConversationItem({
|
|
138
|
+
...item,
|
|
139
|
+
content: convertToLocalContent(item.content),
|
|
140
|
+
}));
|
|
141
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-gen-ai",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.42.0-alpha.0",
|
|
4
4
|
"description": "GoodData GenAI SDK",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -56,18 +56,18 @@
|
|
|
56
56
|
"reselect": "5.1.1",
|
|
57
57
|
"tslib": "2.8.1",
|
|
58
58
|
"uuid": "11.1.1",
|
|
59
|
-
"@gooddata/
|
|
60
|
-
"@gooddata/
|
|
61
|
-
"@gooddata/sdk-model": "11.
|
|
62
|
-
"@gooddata/sdk-ui": "11.
|
|
63
|
-
"@gooddata/sdk-ui
|
|
64
|
-
"@gooddata/sdk-ui-
|
|
65
|
-
"@gooddata/sdk-ui-
|
|
66
|
-
"@gooddata/sdk-ui-kit": "11.
|
|
67
|
-
"@gooddata/sdk-ui-pivot": "11.
|
|
68
|
-
"@gooddata/sdk-ui-semantic-search": "11.
|
|
69
|
-
"@gooddata/sdk-ui-theme-provider": "11.
|
|
70
|
-
"@gooddata/util": "11.
|
|
59
|
+
"@gooddata/sdk-backend-spi": "11.42.0-alpha.0",
|
|
60
|
+
"@gooddata/api-client-tiger": "11.42.0-alpha.0",
|
|
61
|
+
"@gooddata/sdk-model": "11.42.0-alpha.0",
|
|
62
|
+
"@gooddata/sdk-ui-charts": "11.42.0-alpha.0",
|
|
63
|
+
"@gooddata/sdk-ui": "11.42.0-alpha.0",
|
|
64
|
+
"@gooddata/sdk-ui-filters": "11.42.0-alpha.0",
|
|
65
|
+
"@gooddata/sdk-ui-dashboard": "11.42.0-alpha.0",
|
|
66
|
+
"@gooddata/sdk-ui-kit": "11.42.0-alpha.0",
|
|
67
|
+
"@gooddata/sdk-ui-pivot": "11.42.0-alpha.0",
|
|
68
|
+
"@gooddata/sdk-ui-semantic-search": "11.42.0-alpha.0",
|
|
69
|
+
"@gooddata/sdk-ui-theme-provider": "11.42.0-alpha.0",
|
|
70
|
+
"@gooddata/util": "11.42.0-alpha.0"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@microsoft/api-documenter": "^7.17.0",
|
|
@@ -110,13 +110,13 @@
|
|
|
110
110
|
"typescript": "5.9.3",
|
|
111
111
|
"vitest": "4.1.8",
|
|
112
112
|
"vitest-dom": "0.1.1",
|
|
113
|
-
"@gooddata/eslint-config": "11.
|
|
114
|
-
"@gooddata/i18n-toolkit": "11.
|
|
115
|
-
"@gooddata/
|
|
116
|
-
"@gooddata/
|
|
117
|
-
"@gooddata/sdk-backend-mockingbird": "11.
|
|
118
|
-
"@gooddata/
|
|
119
|
-
"@gooddata/
|
|
113
|
+
"@gooddata/eslint-config": "11.42.0-alpha.0",
|
|
114
|
+
"@gooddata/i18n-toolkit": "11.42.0-alpha.0",
|
|
115
|
+
"@gooddata/reference-workspace": "11.42.0-alpha.0",
|
|
116
|
+
"@gooddata/oxlint-config": "11.42.0-alpha.0",
|
|
117
|
+
"@gooddata/sdk-backend-mockingbird": "11.42.0-alpha.0",
|
|
118
|
+
"@gooddata/stylelint-config": "11.42.0-alpha.0",
|
|
119
|
+
"@gooddata/sdk-ui-theme-provider": "11.42.0-alpha.0"
|
|
120
120
|
},
|
|
121
121
|
"peerDependencies": {
|
|
122
122
|
"react": "^18.0.0 || ^19.0.0",
|