@lobehub/chat 0.151.1 → 0.151.2
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 +25 -0
- package/next.config.mjs +1 -0
- package/package.json +2 -2
- package/src/app/chat/(desktop)/features/ChatInput/Footer/SendMore.tsx +2 -2
- package/src/features/ChatInput/useSend.ts +8 -2
- package/src/features/Conversation/components/InboxWelcome/QuestionSuggest.tsx +8 -8
- package/src/features/Conversation/components/VirtualizedList/index.tsx +7 -1
- package/src/features/Conversation/index.tsx +6 -9
- package/src/services/chat.ts +8 -2
- package/src/store/chat/slices/message/action.test.ts +1 -5
- package/src/store/chat/slices/message/action.ts +23 -10
- package/src/store/chat/slices/plugin/action.test.ts +1 -1
- package/src/store/chat/slices/plugin/action.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.151.2](https://github.com/lobehub/lobe-chat/compare/v0.151.1...v0.151.2)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-04-29**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: Fix only inject welcome question in inbox.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: Fix only inject welcome question in inbox, closes [#2289](https://github.com/lobehub/lobe-chat/issues/2289) ([cc8edd3](https://github.com/lobehub/lobe-chat/commit/cc8edd3))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
### [Version 0.151.1](https://github.com/lobehub/lobe-chat/compare/v0.151.0...v0.151.1)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2024-04-29**</sup>
|
package/next.config.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.151.
|
|
3
|
+
"version": "0.151.2",
|
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
"lucide-react": "latest",
|
|
127
127
|
"modern-screenshot": "^4.4.39",
|
|
128
128
|
"nanoid": "^5.0.7",
|
|
129
|
-
"next": "14.1
|
|
129
|
+
"next": "^14.2.1",
|
|
130
130
|
"next-auth": "5.0.0-beta.15",
|
|
131
131
|
"next-sitemap": "^4.2.3",
|
|
132
132
|
"numeral": "^2.0.6",
|
|
@@ -45,7 +45,7 @@ const SendMore = memo(() => {
|
|
|
45
45
|
hotKey,
|
|
46
46
|
(keyboardEvent, hotkeysEvent) => {
|
|
47
47
|
console.log(keyboardEvent, hotkeysEvent);
|
|
48
|
-
sendMessage(true);
|
|
48
|
+
sendMessage({ onlyAddUserMessage: true });
|
|
49
49
|
},
|
|
50
50
|
{
|
|
51
51
|
enableOnFormTags: true,
|
|
@@ -94,7 +94,7 @@ const SendMore = memo(() => {
|
|
|
94
94
|
</Flexbox>
|
|
95
95
|
),
|
|
96
96
|
onClick: () => {
|
|
97
|
-
sendMessage(true);
|
|
97
|
+
sendMessage({ onlyAddUserMessage: true });
|
|
98
98
|
},
|
|
99
99
|
},
|
|
100
100
|
],
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
|
|
3
3
|
import { useChatStore } from '@/store/chat';
|
|
4
|
+
import { SendMessageParams } from '@/store/chat/slices/message/action';
|
|
4
5
|
import { filesSelectors, useFileStore } from '@/store/file';
|
|
5
6
|
|
|
7
|
+
export type UseSendMessageParams = Pick<
|
|
8
|
+
SendMessageParams,
|
|
9
|
+
'onlyAddUserMessage' | 'isWelcomeQuestion'
|
|
10
|
+
>;
|
|
11
|
+
|
|
6
12
|
export const useSendMessage = () => {
|
|
7
13
|
const [sendMessage, updateInputMessage] = useChatStore((s) => [
|
|
8
14
|
s.sendMessage,
|
|
9
15
|
s.updateInputMessage,
|
|
10
16
|
]);
|
|
11
17
|
|
|
12
|
-
return useCallback((
|
|
18
|
+
return useCallback((params: UseSendMessageParams = {}) => {
|
|
13
19
|
const store = useChatStore.getState();
|
|
14
20
|
if (!!store.chatLoadingId) return;
|
|
15
21
|
if (!store.inputMessage) return;
|
|
@@ -19,7 +25,7 @@ export const useSendMessage = () => {
|
|
|
19
25
|
sendMessage({
|
|
20
26
|
files: imageList,
|
|
21
27
|
message: store.inputMessage,
|
|
22
|
-
|
|
28
|
+
...params,
|
|
23
29
|
});
|
|
24
30
|
|
|
25
31
|
updateInputMessage('');
|
|
@@ -10,7 +10,8 @@ import { useTranslation } from 'react-i18next';
|
|
|
10
10
|
import { Flexbox } from 'react-layout-kit';
|
|
11
11
|
|
|
12
12
|
import { USAGE_DOCUMENTS } from '@/const/url';
|
|
13
|
-
import {
|
|
13
|
+
import { useSendMessage } from '@/features/ChatInput/useSend';
|
|
14
|
+
import { useChatStore } from '@/store/chat';
|
|
14
15
|
|
|
15
16
|
const useStyles = createStyles(({ css, token }) => ({
|
|
16
17
|
card: css`
|
|
@@ -54,14 +55,10 @@ const qa = shuffle([
|
|
|
54
55
|
]).slice(0, 5);
|
|
55
56
|
|
|
56
57
|
const QuestionSuggest = memo(() => {
|
|
57
|
-
const
|
|
58
|
+
const [updateInputMessage] = useChatStore((s) => [s.updateInputMessage]);
|
|
58
59
|
const { t } = useTranslation('welcome');
|
|
59
60
|
const { styles } = useStyles();
|
|
60
|
-
|
|
61
|
-
const handoleSend = (qa: string) => {
|
|
62
|
-
onInput(qa);
|
|
63
|
-
onSend();
|
|
64
|
-
};
|
|
61
|
+
const sendMessage = useSendMessage();
|
|
65
62
|
|
|
66
63
|
return (
|
|
67
64
|
<Flexbox gap={8} width={'100%'}>
|
|
@@ -85,7 +82,10 @@ const QuestionSuggest = memo(() => {
|
|
|
85
82
|
gap={8}
|
|
86
83
|
horizontal
|
|
87
84
|
key={item}
|
|
88
|
-
onClick={() =>
|
|
85
|
+
onClick={() => {
|
|
86
|
+
updateInputMessage(text);
|
|
87
|
+
sendMessage({ isWelcomeQuestion: true });
|
|
88
|
+
}}
|
|
89
89
|
>
|
|
90
90
|
{t(text)}
|
|
91
91
|
</Flexbox>
|
|
@@ -7,9 +7,11 @@ import { useChatStore } from '@/store/chat';
|
|
|
7
7
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
8
8
|
import { isMobileScreen } from '@/utils/screen';
|
|
9
9
|
|
|
10
|
+
import { useInitConversation } from '../../hooks/useInitConversation';
|
|
10
11
|
import AutoScroll from '../AutoScroll';
|
|
11
12
|
import Item from '../ChatItem';
|
|
12
13
|
import InboxWelcome from '../InboxWelcome';
|
|
14
|
+
import SkeletonList from '../SkeletonList';
|
|
13
15
|
|
|
14
16
|
const WELCOME_ID = 'welcome';
|
|
15
17
|
|
|
@@ -29,6 +31,8 @@ interface VirtualizedListProps {
|
|
|
29
31
|
mobile?: boolean;
|
|
30
32
|
}
|
|
31
33
|
const VirtualizedList = memo<VirtualizedListProps>(({ mobile }) => {
|
|
34
|
+
useInitConversation();
|
|
35
|
+
|
|
32
36
|
const virtuosoRef = useRef<VirtuosoHandle>(null);
|
|
33
37
|
const [atBottom, setAtBottom] = useState(true);
|
|
34
38
|
|
|
@@ -52,7 +56,9 @@ const VirtualizedList = memo<VirtualizedListProps>(({ mobile }) => {
|
|
|
52
56
|
// overscan should be 1.5 times the height of the window
|
|
53
57
|
const overscan = typeof window !== 'undefined' ? window.innerHeight * 1.5 : 0;
|
|
54
58
|
|
|
55
|
-
return chatLoading
|
|
59
|
+
return chatLoading ? (
|
|
60
|
+
<SkeletonList mobile={mobile} />
|
|
61
|
+
) : (
|
|
56
62
|
<Flexbox height={'100%'}>
|
|
57
63
|
<Virtuoso
|
|
58
64
|
atBottomStateChange={setAtBottom}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { createStyles } from 'antd-style';
|
|
2
|
-
import { ReactNode, memo } from 'react';
|
|
2
|
+
import { ReactNode, Suspense, lazy, memo } from 'react';
|
|
3
3
|
import { Flexbox } from 'react-layout-kit';
|
|
4
4
|
|
|
5
5
|
import ChatHydration from '@/components/StoreHydration/ChatHydration';
|
|
6
|
-
import { useChatStore } from '@/store/chat';
|
|
7
6
|
|
|
8
7
|
import SkeletonList from './components/SkeletonList';
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
|
|
9
|
+
const ChatList = lazy(() => import('./components/VirtualizedList'));
|
|
11
10
|
|
|
12
11
|
const useStyles = createStyles(
|
|
13
12
|
({ css, responsive, stylish }) => css`
|
|
@@ -30,10 +29,6 @@ interface ConversationProps {
|
|
|
30
29
|
const Conversation = memo<ConversationProps>(({ chatInput, mobile }) => {
|
|
31
30
|
const { styles } = useStyles();
|
|
32
31
|
|
|
33
|
-
useInitConversation();
|
|
34
|
-
|
|
35
|
-
const [messagesInit] = useChatStore((s) => [s.messagesInit]);
|
|
36
|
-
|
|
37
32
|
return (
|
|
38
33
|
<Flexbox
|
|
39
34
|
flex={1}
|
|
@@ -41,7 +36,9 @@ const Conversation = memo<ConversationProps>(({ chatInput, mobile }) => {
|
|
|
41
36
|
style={{ position: 'relative' }}
|
|
42
37
|
>
|
|
43
38
|
<div className={styles}>
|
|
44
|
-
|
|
39
|
+
<Suspense fallback={<SkeletonList mobile={mobile} />}>
|
|
40
|
+
<ChatList mobile={mobile} />
|
|
41
|
+
</Suspense>
|
|
45
42
|
</div>
|
|
46
43
|
{chatInput}
|
|
47
44
|
<ChatHydration />
|
package/src/services/chat.ts
CHANGED
|
@@ -31,6 +31,7 @@ import { createHeaderWithAuth, getProviderAuthPayload } from './_auth';
|
|
|
31
31
|
import { API_ENDPOINTS } from './_url';
|
|
32
32
|
|
|
33
33
|
interface FetchOptions {
|
|
34
|
+
isWelcomeQuestion?: boolean;
|
|
34
35
|
signal?: AbortSignal | undefined;
|
|
35
36
|
trace?: TracePayload;
|
|
36
37
|
}
|
|
@@ -65,6 +66,7 @@ interface FetchAITaskResultParams {
|
|
|
65
66
|
|
|
66
67
|
interface CreateAssistantMessageStream extends FetchSSEOptions {
|
|
67
68
|
abortController?: AbortController;
|
|
69
|
+
isWelcomeQuestion?: boolean;
|
|
68
70
|
params: GetChatCompletionPayload;
|
|
69
71
|
trace?: TracePayload;
|
|
70
72
|
}
|
|
@@ -220,10 +222,12 @@ class ChatService {
|
|
|
220
222
|
onErrorHandle,
|
|
221
223
|
onFinish,
|
|
222
224
|
trace,
|
|
225
|
+
isWelcomeQuestion,
|
|
223
226
|
}: CreateAssistantMessageStream) => {
|
|
224
227
|
await fetchSSE(
|
|
225
228
|
() =>
|
|
226
229
|
this.createAssistantMessage(params, {
|
|
230
|
+
isWelcomeQuestion,
|
|
227
231
|
signal: abortController?.signal,
|
|
228
232
|
trace: this.mapTrace(trace, TraceTagMap.Chat),
|
|
229
233
|
}),
|
|
@@ -432,9 +436,11 @@ class ChatService {
|
|
|
432
436
|
});
|
|
433
437
|
|
|
434
438
|
return produce(postMessages, (draft) => {
|
|
435
|
-
//
|
|
439
|
+
// if it's a welcome question, inject InboxGuide SystemRole
|
|
436
440
|
const inboxGuideSystemRole =
|
|
437
|
-
options?.
|
|
441
|
+
options?.isWelcomeQuestion &&
|
|
442
|
+
options?.trace?.sessionId === INBOX_SESSION_ID &&
|
|
443
|
+
INBOX_GUIDE_SYSTEMROLE;
|
|
438
444
|
|
|
439
445
|
// Inject Tool SystemRole
|
|
440
446
|
const hasTools = tools && tools?.length > 0;
|
|
@@ -385,11 +385,7 @@ describe('chatMessage actions', () => {
|
|
|
385
385
|
});
|
|
386
386
|
|
|
387
387
|
expect(messageService.removeMessage).not.toHaveBeenCalledWith(messageId);
|
|
388
|
-
expect(mockState.coreProcessMessage).toHaveBeenCalledWith(
|
|
389
|
-
expect.any(Array),
|
|
390
|
-
messageId,
|
|
391
|
-
undefined,
|
|
392
|
-
);
|
|
388
|
+
expect(mockState.coreProcessMessage).toHaveBeenCalledWith(expect.any(Array), messageId, {});
|
|
393
389
|
});
|
|
394
390
|
|
|
395
391
|
it('should not perform any action if the message id does not exist', async () => {
|
|
@@ -29,10 +29,20 @@ const n = setNamespace('message');
|
|
|
29
29
|
|
|
30
30
|
const SWR_USE_FETCH_MESSAGES = 'SWR_USE_FETCH_MESSAGES';
|
|
31
31
|
|
|
32
|
-
interface SendMessageParams {
|
|
32
|
+
export interface SendMessageParams {
|
|
33
33
|
message: string;
|
|
34
34
|
files?: { id: string; url: string }[];
|
|
35
35
|
onlyAddUserMessage?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
* https://github.com/lobehub/lobe-chat/pull/2086
|
|
39
|
+
*/
|
|
40
|
+
isWelcomeQuestion?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface ProcessMessageParams {
|
|
44
|
+
traceId?: string;
|
|
45
|
+
isWelcomeQuestion?: boolean;
|
|
36
46
|
}
|
|
37
47
|
|
|
38
48
|
export interface ChatMessageAction {
|
|
@@ -77,7 +87,7 @@ export interface ChatMessageAction {
|
|
|
77
87
|
coreProcessMessage: (
|
|
78
88
|
messages: ChatMessage[],
|
|
79
89
|
parentId: string,
|
|
80
|
-
|
|
90
|
+
params?: ProcessMessageParams,
|
|
81
91
|
) => Promise<void>;
|
|
82
92
|
/**
|
|
83
93
|
* 实际获取 AI 响应
|
|
@@ -87,7 +97,7 @@ export interface ChatMessageAction {
|
|
|
87
97
|
fetchAIChatMessage: (
|
|
88
98
|
messages: ChatMessage[],
|
|
89
99
|
assistantMessageId: string,
|
|
90
|
-
|
|
100
|
+
params?: ProcessMessageParams,
|
|
91
101
|
) => Promise<{
|
|
92
102
|
content: string;
|
|
93
103
|
functionCallAtEnd: boolean;
|
|
@@ -173,7 +183,7 @@ export const chatMessage: StateCreator<
|
|
|
173
183
|
await messageService.removeAllMessages();
|
|
174
184
|
await refreshMessages();
|
|
175
185
|
},
|
|
176
|
-
sendMessage: async ({ message, files, onlyAddUserMessage }) => {
|
|
186
|
+
sendMessage: async ({ message, files, onlyAddUserMessage, isWelcomeQuestion }) => {
|
|
177
187
|
const { coreProcessMessage, activeTopicId, activeId } = get();
|
|
178
188
|
if (!activeId) return;
|
|
179
189
|
|
|
@@ -200,7 +210,7 @@ export const chatMessage: StateCreator<
|
|
|
200
210
|
// Get the current messages to generate AI response
|
|
201
211
|
const messages = chatSelectors.currentChats(get());
|
|
202
212
|
|
|
203
|
-
await coreProcessMessage(messages, id);
|
|
213
|
+
await coreProcessMessage(messages, id, { isWelcomeQuestion });
|
|
204
214
|
|
|
205
215
|
// check activeTopic and then auto create topic
|
|
206
216
|
const chats = chatSelectors.currentChats(get());
|
|
@@ -263,6 +273,8 @@ export const chatMessage: StateCreator<
|
|
|
263
273
|
async ([, sessionId, topicId]: [string, string, string | undefined]) =>
|
|
264
274
|
messageService.getMessages(sessionId, topicId),
|
|
265
275
|
{
|
|
276
|
+
suspense: true,
|
|
277
|
+
fallbackData: [],
|
|
266
278
|
onSuccess: (messages, key) => {
|
|
267
279
|
set(
|
|
268
280
|
{ activeId: sessionId, messages, messagesInit: true },
|
|
@@ -280,7 +292,7 @@ export const chatMessage: StateCreator<
|
|
|
280
292
|
},
|
|
281
293
|
|
|
282
294
|
// the internal process method of the AI message
|
|
283
|
-
coreProcessMessage: async (messages, userMessageId,
|
|
295
|
+
coreProcessMessage: async (messages, userMessageId, params) => {
|
|
284
296
|
const { fetchAIChatMessage, triggerFunctionCall, refreshMessages, activeTopicId } = get();
|
|
285
297
|
|
|
286
298
|
const { model, provider } = getAgentConfig();
|
|
@@ -301,7 +313,7 @@ export const chatMessage: StateCreator<
|
|
|
301
313
|
|
|
302
314
|
// 2. fetch the AI response
|
|
303
315
|
const { isFunctionCall, content, functionCallAtEnd, functionCallContent, traceId } =
|
|
304
|
-
await fetchAIChatMessage(messages, mid,
|
|
316
|
+
await fetchAIChatMessage(messages, mid, params);
|
|
305
317
|
|
|
306
318
|
// 3. if it's the function call message, trigger the function method
|
|
307
319
|
if (isFunctionCall) {
|
|
@@ -341,7 +353,7 @@ export const chatMessage: StateCreator<
|
|
|
341
353
|
|
|
342
354
|
set({ messages }, false, n(`dispatchMessage/${payload.type}`, payload));
|
|
343
355
|
},
|
|
344
|
-
fetchAIChatMessage: async (messages, assistantId,
|
|
356
|
+
fetchAIChatMessage: async (messages, assistantId, params) => {
|
|
345
357
|
const {
|
|
346
358
|
toggleChatLoading,
|
|
347
359
|
refreshMessages,
|
|
@@ -421,11 +433,12 @@ export const chatMessage: StateCreator<
|
|
|
421
433
|
plugins: config.plugins,
|
|
422
434
|
},
|
|
423
435
|
trace: {
|
|
424
|
-
traceId,
|
|
436
|
+
traceId: params?.traceId,
|
|
425
437
|
sessionId: get().activeId,
|
|
426
438
|
topicId: get().activeTopicId,
|
|
427
439
|
traceName: TraceNameMap.Conversation,
|
|
428
440
|
},
|
|
441
|
+
isWelcomeQuestion: params?.isWelcomeQuestion,
|
|
429
442
|
onErrorHandle: async (error) => {
|
|
430
443
|
await messageService.updateMessageError(assistantId, error);
|
|
431
444
|
await refreshMessages();
|
|
@@ -567,7 +580,7 @@ export const chatMessage: StateCreator<
|
|
|
567
580
|
|
|
568
581
|
if (!latestMsg) return;
|
|
569
582
|
|
|
570
|
-
await coreProcessMessage(contextMessages, latestMsg.id, traceId);
|
|
583
|
+
await coreProcessMessage(contextMessages, latestMsg.id, { traceId });
|
|
571
584
|
},
|
|
572
585
|
|
|
573
586
|
internalUpdateMessageContent: async (id, content) => {
|
|
@@ -174,7 +174,7 @@ export const chatPlugin: StateCreator<
|
|
|
174
174
|
triggerAIMessage: async (id, traceId) => {
|
|
175
175
|
const { coreProcessMessage } = get();
|
|
176
176
|
const chats = chatSelectors.currentChats(get());
|
|
177
|
-
await coreProcessMessage(chats, id, traceId);
|
|
177
|
+
await coreProcessMessage(chats, id, { traceId });
|
|
178
178
|
},
|
|
179
179
|
|
|
180
180
|
triggerFunctionCall: async (id) => {
|