@red-hat-developer-hub/backstage-plugin-lightspeed 2.5.0 → 2.6.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/CHANGELOG.md +16 -0
- package/README.md +6 -2
- package/dist/alpha.d.ts +5 -0
- package/dist/components/LightSpeedChat.esm.js +92 -21
- package/dist/components/LightSpeedChat.esm.js.map +1 -1
- package/dist/components/LightspeedDrawerContext.esm.js.map +1 -1
- package/dist/components/notebooks/AddDocumentModal.esm.js +122 -23
- package/dist/components/notebooks/AddDocumentModal.esm.js.map +1 -1
- package/dist/components/notebooks/DocumentSidebar.esm.js +19 -1
- package/dist/components/notebooks/DocumentSidebar.esm.js.map +1 -1
- package/dist/components/notebooks/FileListItem.esm.js +94 -0
- package/dist/components/notebooks/FileListItem.esm.js.map +1 -0
- package/dist/components/notebooks/NotebookView.esm.js +46 -26
- package/dist/components/notebooks/NotebookView.esm.js.map +1 -1
- package/dist/components/notebooks/OverwriteConfirmModal.esm.js +2 -1
- package/dist/components/notebooks/OverwriteConfirmModal.esm.js.map +1 -1
- package/dist/components/notebooks/SidebarCollapseIcon.esm.js +5 -2
- package/dist/components/notebooks/SidebarCollapseIcon.esm.js.map +1 -1
- package/dist/hooks/toolCallsCacheStore.esm.js +61 -0
- package/dist/hooks/toolCallsCacheStore.esm.js.map +1 -0
- package/dist/hooks/useConversationMessages.esm.js +359 -325
- package/dist/hooks/useConversationMessages.esm.js.map +1 -1
- package/dist/hooks/useDeleteConversation.esm.js +2 -0
- package/dist/hooks/useDeleteConversation.esm.js.map +1 -1
- package/dist/hooks/useLightspeedProviderState.esm.js +35 -8
- package/dist/hooks/useLightspeedProviderState.esm.js.map +1 -1
- package/dist/translations/de.esm.js +5 -0
- package/dist/translations/de.esm.js.map +1 -1
- package/dist/translations/es.esm.js +5 -0
- package/dist/translations/es.esm.js.map +1 -1
- package/dist/translations/fr.esm.js +5 -0
- package/dist/translations/fr.esm.js.map +1 -1
- package/dist/translations/it.esm.js +5 -0
- package/dist/translations/it.esm.js.map +1 -1
- package/dist/translations/ja.esm.js +5 -0
- package/dist/translations/ja.esm.js.map +1 -1
- package/dist/translations/ref.esm.js +5 -0
- package/dist/translations/ref.esm.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
## @red-hat-developer-hub/backstage-plugin-lightspeed
|
|
2
2
|
|
|
3
|
+
## 2.6.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9f5f22a: Fix new chat streams when switching threads and scope Stop to the streaming conversation (RHDHBUGS-3040).
|
|
8
|
+
- @red-hat-developer-hub/backstage-plugin-lightspeed-common@2.6.0
|
|
9
|
+
|
|
10
|
+
## 2.5.1
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- d621f93: Improved notebook upload modal and MessageBar UX.
|
|
15
|
+
- d621f93: Fixed overwrite flow to add duplicate files to the Add Document modal instead of uploading immediately. Reduced notebook delete toast timeout to 2 seconds.
|
|
16
|
+
- 5d17950: Retain Lightspeed chat and tool-call state when the chat UI remounts (for example when switching display mode between embedded and overlay), so the active thread and tool metadata are not dropped while messages are still streaming or before history refetches.
|
|
17
|
+
- @red-hat-developer-hub/backstage-plugin-lightspeed-common@2.5.1
|
|
18
|
+
|
|
3
19
|
## 2.5.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -85,7 +85,11 @@ Lightspeed is a front-end plugin that enables you to interact with any LLM serve
|
|
|
85
85
|
#### Procedure
|
|
86
86
|
|
|
87
87
|
1. Open your Backstage application and select a Lightspeed nav item from the **Navigation**.
|
|
88
|
-
2. Ask
|
|
88
|
+
2. Ask your questions to the Lightspeed chatbot.
|
|
89
|
+
|
|
90
|
+
### Display modes and chat continuity
|
|
91
|
+
|
|
92
|
+
Lightspeed supports multiple **display modes** from Settings (for example overlay, docked, embedded, and fullscreen). Switching modes can remount the chat surface; your **current conversation** and **tool-call metadata** for that thread stay with the session so the active chat is not reset. Live streaming text may not update continuously across a mode switch until the assistant response finishes loading.
|
|
89
93
|
|
|
90
94
|
### MCP servers settings
|
|
91
95
|
|
|
@@ -129,7 +133,7 @@ Notebooks is an experimental feature that enables **document-based conversations
|
|
|
129
133
|
|
|
130
134
|
#### Prerequisites for Notebooks
|
|
131
135
|
|
|
132
|
-
- Notebooks requires a **
|
|
136
|
+
- Notebooks requires a **Lightspeed Stack service** to be running
|
|
133
137
|
- The backend administrator must enable the feature (see [Backend Configuration](../lightspeed-backend/README.md#notebooks-developer-preview))
|
|
134
138
|
- Users need the appropriate RBAC permissions (if enabled)
|
|
135
139
|
|
package/dist/alpha.d.ts
CHANGED
|
@@ -66,10 +66,12 @@ declare const lightspeedTranslationRef: _backstage_frontend_plugin_api.Translati
|
|
|
66
66
|
readonly "notebook.view.upload.heading": string;
|
|
67
67
|
readonly "notebook.view.upload.action": string;
|
|
68
68
|
readonly "notebook.view.input.placeholder": string;
|
|
69
|
+
readonly "notebook.view.input.disabledTooltip": string;
|
|
69
70
|
readonly "notebook.view.sidebar.collapse": string;
|
|
70
71
|
readonly "notebook.view.sidebar.expand": string;
|
|
71
72
|
readonly "notebook.view.sidebar.resize": string;
|
|
72
73
|
readonly "notebook.view.documents.uploading": string;
|
|
74
|
+
readonly "notebook.view.documents.maxReached": string;
|
|
73
75
|
readonly "notebook.upload.success": string;
|
|
74
76
|
readonly "notebook.upload.failed": string;
|
|
75
77
|
readonly "notebook.upload.modal.title": string;
|
|
@@ -77,6 +79,9 @@ declare const lightspeedTranslationRef: _backstage_frontend_plugin_api.Translati
|
|
|
77
79
|
readonly "notebook.upload.modal.browseButton": string;
|
|
78
80
|
readonly "notebook.upload.modal.separator": string;
|
|
79
81
|
readonly "notebook.upload.modal.infoText": string;
|
|
82
|
+
readonly "notebook.upload.modal.selectedFiles": string;
|
|
83
|
+
readonly "notebook.upload.modal.addButton": string;
|
|
84
|
+
readonly "notebook.upload.modal.removeFile": string;
|
|
80
85
|
readonly "notebook.upload.error.unsupportedType": string;
|
|
81
86
|
readonly "notebook.upload.error.fileTooLarge": string;
|
|
82
87
|
readonly "notebook.upload.error.tooManyFiles": string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useState, useEffect, useRef, useCallback,
|
|
2
|
+
import { useState, useEffect, useRef, useCallback, useLayoutEffect, useMemo } from 'react';
|
|
3
3
|
import { useNavigate, useMatch } from 'react-router-dom';
|
|
4
4
|
import { makeStyles, Button } from '@material-ui/core';
|
|
5
5
|
import { ChatbotDisplayMode, ChatbotContent, ChatbotFooter, MessageBar, ChatbotFootnote, Settings, Chatbot, ChatbotHeader, ChatbotHeaderMain, ChatbotHeaderMenu, ChatbotHeaderTitle, FileDropZone, ChatbotAlert } from '@patternfly/chatbot';
|
|
@@ -452,7 +452,8 @@ const LightspeedChat = ({
|
|
|
452
452
|
currentConversationId: routeConversationId,
|
|
453
453
|
setCurrentConversationId,
|
|
454
454
|
draftMessage,
|
|
455
|
-
setDraftMessage
|
|
455
|
+
setDraftMessage,
|
|
456
|
+
consumePendingOverlayThreadHandoff
|
|
456
457
|
} = useLightspeedDrawerContext();
|
|
457
458
|
const isFullscreenMode = displayMode === ChatbotDisplayMode.embedded;
|
|
458
459
|
const showChatPanel = !isFullscreenMode || activeTab === 0;
|
|
@@ -529,11 +530,44 @@ const LightspeedChat = ({
|
|
|
529
530
|
handleFileUpload,
|
|
530
531
|
setUploadError
|
|
531
532
|
} = useFileAttachmentContext();
|
|
533
|
+
useLayoutEffect(() => {
|
|
534
|
+
if (!isReady) return;
|
|
535
|
+
if (isFullscreenMode) {
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
const handoff = consumePendingOverlayThreadHandoff?.() ?? false;
|
|
539
|
+
if (handoff) {
|
|
540
|
+
if (routeConversationId) {
|
|
541
|
+
setConversationId(routeConversationId);
|
|
542
|
+
setNewChatCreated(false);
|
|
543
|
+
} else {
|
|
544
|
+
setConversationId(TEMP_CONVERSATION_ID);
|
|
545
|
+
setNewChatCreated(true);
|
|
546
|
+
}
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
if (routeConversationId && routeConversationId !== conversationId) {
|
|
550
|
+
setConversationId(routeConversationId);
|
|
551
|
+
setNewChatCreated(false);
|
|
552
|
+
} else if (!routeConversationId && conversationId === "" && lastOpenedId !== null) {
|
|
553
|
+
setConversationId(lastOpenedId);
|
|
554
|
+
}
|
|
555
|
+
}, [
|
|
556
|
+
isReady,
|
|
557
|
+
isFullscreenMode,
|
|
558
|
+
routeConversationId,
|
|
559
|
+
conversationId,
|
|
560
|
+
lastOpenedId,
|
|
561
|
+
consumePendingOverlayThreadHandoff
|
|
562
|
+
]);
|
|
532
563
|
useEffect(() => {
|
|
533
|
-
if (isReady
|
|
564
|
+
if (!isReady || !isFullscreenMode) {
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (lastOpenedId !== null) {
|
|
534
568
|
setConversationId(lastOpenedId);
|
|
535
569
|
}
|
|
536
|
-
}, [lastOpenedId, isReady]);
|
|
570
|
+
}, [lastOpenedId, isReady, isFullscreenMode]);
|
|
537
571
|
const queryClient = useQueryClient();
|
|
538
572
|
const {
|
|
539
573
|
data: conversations = [],
|
|
@@ -545,27 +579,53 @@ const LightspeedChat = ({
|
|
|
545
579
|
const samplePrompts = useWelcomePrompts();
|
|
546
580
|
useEffect(() => {
|
|
547
581
|
if (!user || !isReady) return;
|
|
582
|
+
const onOverlayLikeSurface = isFullscreenMode || !routeConversationId;
|
|
583
|
+
const stillOnProvisionalThread = !conversationId || conversationId === TEMP_CONVERSATION_ID;
|
|
548
584
|
if (lastOpenedId === null) {
|
|
549
|
-
|
|
585
|
+
if (onOverlayLikeSurface && stillOnProvisionalThread) {
|
|
586
|
+
setConversationId(TEMP_CONVERSATION_ID);
|
|
587
|
+
}
|
|
550
588
|
}
|
|
551
589
|
if (lastOpenedId === TEMP_CONVERSATION_ID || lastOpenedId === null) {
|
|
552
|
-
|
|
590
|
+
if (onOverlayLikeSurface && stillOnProvisionalThread) {
|
|
591
|
+
setNewChatCreated(true);
|
|
592
|
+
}
|
|
553
593
|
}
|
|
554
|
-
}, [
|
|
594
|
+
}, [
|
|
595
|
+
user,
|
|
596
|
+
isReady,
|
|
597
|
+
lastOpenedId,
|
|
598
|
+
setConversationId,
|
|
599
|
+
isFullscreenMode,
|
|
600
|
+
routeConversationId,
|
|
601
|
+
conversationId
|
|
602
|
+
]);
|
|
555
603
|
useEffect(() => {
|
|
556
604
|
if (!isLoading && !isRefetching && conversations.length === 0 && lastOpenedId) {
|
|
557
605
|
clearLastOpenedId();
|
|
606
|
+
setConversationId(TEMP_CONVERSATION_ID);
|
|
607
|
+
setNewChatCreated(true);
|
|
608
|
+
setCurrentConversationId(undefined);
|
|
558
609
|
}
|
|
559
|
-
}, [
|
|
610
|
+
}, [
|
|
611
|
+
isLoading,
|
|
612
|
+
isRefetching,
|
|
613
|
+
conversations,
|
|
614
|
+
lastOpenedId,
|
|
615
|
+
clearLastOpenedId,
|
|
616
|
+
setCurrentConversationId
|
|
617
|
+
]);
|
|
560
618
|
useEffect(() => {
|
|
561
619
|
if (!isLoading && !isRefetching && routeConversationId && isFullscreenMode) {
|
|
562
620
|
const conversationExists = conversations.some(
|
|
563
621
|
(c) => c.conversation_id === routeConversationId
|
|
564
622
|
);
|
|
565
623
|
if (!conversationExists) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
624
|
+
if (routeConversationId !== conversationId) {
|
|
625
|
+
setConversationId(TEMP_CONVERSATION_ID);
|
|
626
|
+
setCurrentConversationId(undefined);
|
|
627
|
+
setNewChatCreated(true);
|
|
628
|
+
}
|
|
569
629
|
} else if (conversationId !== routeConversationId) {
|
|
570
630
|
setConversationId(routeConversationId);
|
|
571
631
|
}
|
|
@@ -585,6 +645,10 @@ const LightspeedChat = ({
|
|
|
585
645
|
setLastOpenedId(conversationId);
|
|
586
646
|
}
|
|
587
647
|
}, [conversationId, setLastOpenedId]);
|
|
648
|
+
const viewConversationId = useMemo(
|
|
649
|
+
() => !isFullscreenMode && routeConversationId ? routeConversationId : conversationId,
|
|
650
|
+
[isFullscreenMode, routeConversationId, conversationId]
|
|
651
|
+
);
|
|
588
652
|
const onStart = (conv_id) => {
|
|
589
653
|
setConversationId(conv_id);
|
|
590
654
|
setCurrentConversationId(conv_id);
|
|
@@ -602,12 +666,17 @@ const LightspeedChat = ({
|
|
|
602
666
|
queryKey: ["conversations"]
|
|
603
667
|
});
|
|
604
668
|
queryClient.invalidateQueries({
|
|
605
|
-
queryKey: ["conversationMessages",
|
|
669
|
+
queryKey: ["conversationMessages", viewConversationId]
|
|
606
670
|
});
|
|
607
671
|
setNewChatCreated(false);
|
|
608
672
|
};
|
|
609
|
-
const {
|
|
610
|
-
|
|
673
|
+
const {
|
|
674
|
+
conversationMessages,
|
|
675
|
+
handleInputPrompt,
|
|
676
|
+
scrollToBottomRef,
|
|
677
|
+
streamingConversationId
|
|
678
|
+
} = useConversationMessages(
|
|
679
|
+
viewConversationId,
|
|
611
680
|
userName,
|
|
612
681
|
selectedModel,
|
|
613
682
|
selectedProvider,
|
|
@@ -617,11 +686,12 @@ const LightspeedChat = ({
|
|
|
617
686
|
undefined,
|
|
618
687
|
onRequestIdReady
|
|
619
688
|
);
|
|
689
|
+
const streamingUiMatchesView = isSendButtonDisabled && streamingConversationId !== null && viewConversationId === streamingConversationId;
|
|
620
690
|
const [messages, setMessages] = useState(conversationMessages);
|
|
621
691
|
const sendMessage = (message) => {
|
|
622
692
|
if (!message.toString().trim()) return;
|
|
623
693
|
wasStoppedByUserRef.current = false;
|
|
624
|
-
if (
|
|
694
|
+
if (viewConversationId !== TEMP_CONVERSATION_ID) {
|
|
625
695
|
setNewChatCreated(false);
|
|
626
696
|
}
|
|
627
697
|
setAnnouncement(
|
|
@@ -839,7 +909,7 @@ const LightspeedChat = ({
|
|
|
839
909
|
]
|
|
840
910
|
);
|
|
841
911
|
const conversationFound = !!conversations.find(
|
|
842
|
-
(c) => c.conversation_id ===
|
|
912
|
+
(c) => c.conversation_id === viewConversationId
|
|
843
913
|
);
|
|
844
914
|
const getMaxPrompts = () => {
|
|
845
915
|
if (isFullscreenMode) {
|
|
@@ -1112,7 +1182,7 @@ const LightspeedChat = ({
|
|
|
1112
1182
|
ref: scrollToBottomRef,
|
|
1113
1183
|
welcomePrompts,
|
|
1114
1184
|
conversationId,
|
|
1115
|
-
isStreaming:
|
|
1185
|
+
isStreaming: streamingUiMatchesView,
|
|
1116
1186
|
topicRestrictionEnabled,
|
|
1117
1187
|
displayMode
|
|
1118
1188
|
}
|
|
@@ -1140,8 +1210,8 @@ const LightspeedChat = ({
|
|
|
1140
1210
|
hasMicrophoneButton: true,
|
|
1141
1211
|
value: draftMessage,
|
|
1142
1212
|
onChange: handleDraftMessage,
|
|
1143
|
-
hasStopButton:
|
|
1144
|
-
handleStopButton:
|
|
1213
|
+
hasStopButton: streamingUiMatchesView,
|
|
1214
|
+
handleStopButton: streamingUiMatchesView ? handleStopButton : undefined,
|
|
1145
1215
|
buttonProps: {
|
|
1146
1216
|
attach: {
|
|
1147
1217
|
inputTestId: "attachment-input",
|
|
@@ -1217,7 +1287,7 @@ const LightspeedChat = ({
|
|
|
1217
1287
|
variant: AlertVariant[variant ?? "success"],
|
|
1218
1288
|
title,
|
|
1219
1289
|
className: classes.toastAlert,
|
|
1220
|
-
timeout:
|
|
1290
|
+
timeout: 2e3,
|
|
1221
1291
|
onTimeout: () => handleRemoveNotebookAlert(key),
|
|
1222
1292
|
actionClose: /* @__PURE__ */ jsx(
|
|
1223
1293
|
AlertActionCloseButton,
|
|
@@ -1342,7 +1412,7 @@ const LightspeedChat = ({
|
|
|
1342
1412
|
"aria-label": t("aria.closeDrawerPanel")
|
|
1343
1413
|
},
|
|
1344
1414
|
setIsDrawerOpen: setIsChatHistoryDrawerOpen,
|
|
1345
|
-
activeItemId:
|
|
1415
|
+
activeItemId: viewConversationId,
|
|
1346
1416
|
onSelectActiveItem,
|
|
1347
1417
|
conversations: filterConversations(filterValue),
|
|
1348
1418
|
onNewChat: newChatCreated ? undefined : onNewChat,
|
|
@@ -1406,6 +1476,7 @@ const LightspeedChat = ({
|
|
|
1406
1476
|
avatar,
|
|
1407
1477
|
profileLoading,
|
|
1408
1478
|
topicRestrictionEnabled,
|
|
1479
|
+
selectedModel,
|
|
1409
1480
|
onClose: handleCloseNotebook
|
|
1410
1481
|
}
|
|
1411
1482
|
),
|