@lobehub/chat 0.44.2 → 0.44.3

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 CHANGED
@@ -2,6 +2,47 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.44.3](https://github.com/lobehub/lobe-chat/compare/v0.44.2...v0.44.3)
6
+
7
+ <sup>Released on **2023-08-13**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: 重构 organizeChats 方法.
12
+
13
+ #### 🐛 Bug Fixes
14
+
15
+ - **misc**: 修正 inbox 点击重新生成会报错的问题.
16
+
17
+ #### 💄 Styles
18
+
19
+ - **misc**: 修正话题列表无法滚动的问题.
20
+
21
+ <br/>
22
+
23
+ <details>
24
+ <summary><kbd>Improvements and Fixes</kbd></summary>
25
+
26
+ #### Code refactoring
27
+
28
+ - **misc**: 重构 organizeChats 方法 ([799612e](https://github.com/lobehub/lobe-chat/commit/799612e))
29
+
30
+ #### What's fixed
31
+
32
+ - **misc**: 修正 inbox 点击重新生成会报错的问题 ([064ef56](https://github.com/lobehub/lobe-chat/commit/064ef56))
33
+
34
+ #### Styles
35
+
36
+ - **misc**: 修正话题列表无法滚动的问题 ([26772e7](https://github.com/lobehub/lobe-chat/commit/26772e7))
37
+
38
+ </details>
39
+
40
+ <div align="right">
41
+
42
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
43
+
44
+ </div>
45
+
5
46
  ### [Version 0.44.2](https://github.com/lobehub/lobe-chat/compare/v0.44.1...v0.44.2)
6
47
 
7
48
  <sup>Released on **2023-08-13**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.44.2",
3
+ "version": "0.44.3",
4
4
  "description": "Lobe Chat is an open-source chatbot client using LangChain, Typescript and Next.js",
5
5
  "keywords": [
6
6
  "chatbot",
@@ -4,7 +4,7 @@ export default {
4
4
  agentMaxToken: '会话最大长度',
5
5
  agentModel: '模型',
6
6
  agentProfile: '助手信息',
7
- appInitializing: '应用加载中...',
7
+ appInitializing: '智能集群启动中,请耐心等待...',
8
8
  archive: '归档',
9
9
  autoGenerate: '自动补全',
10
10
  autoGenerateTooltip: '基于提示词自动补全助手描述',
@@ -52,7 +52,7 @@ const SystemRole = memo(() => {
52
52
  const hydrated = useSessionHydrated();
53
53
  const { t } = useTranslation('common');
54
54
  return (
55
- <>
55
+ <Flexbox height={'fit-content'}>
56
56
  <Header
57
57
  actions={
58
58
  <ActionIcon
@@ -90,7 +90,7 @@ const SystemRole = memo(() => {
90
90
  <Skeleton active avatar={false} style={{ marginTop: 12 }} title={false} />
91
91
  )}
92
92
  </Flexbox>
93
- </>
93
+ </Flexbox>
94
94
  );
95
95
  });
96
96
 
@@ -0,0 +1,22 @@
1
+ import { Skeleton } from 'antd';
2
+ import { memo } from 'react';
3
+ import { Flexbox } from 'react-layout-kit';
4
+
5
+ const SkeletonList = memo(() => {
6
+ return (
7
+ <Flexbox gap={8} style={{ marginTop: 8 }}>
8
+ {Array.from({ length: 8 }).map((_, i) => (
9
+ <Skeleton
10
+ active
11
+ avatar={false}
12
+ key={i}
13
+ paragraph={{ rows: 1, width: '100%' }}
14
+ round
15
+ title={false}
16
+ />
17
+ ))}
18
+ </Flexbox>
19
+ );
20
+ });
21
+
22
+ export default SkeletonList;
@@ -5,11 +5,13 @@ import { Flexbox } from 'react-layout-kit';
5
5
 
6
6
  import Empty from '@/components/Empty';
7
7
  import { useGlobalStore } from '@/store/global';
8
- import { topicSelectors, useSessionStore } from '@/store/session';
8
+ import { topicSelectors, useSessionHydrated, useSessionStore } from '@/store/session';
9
9
 
10
+ import SkeletonList from './SkeletonList';
10
11
  import TopicItem from './TopicItem';
11
12
 
12
13
  export const Topic = () => {
14
+ const hydrated = useSessionHydrated();
13
15
  const topics = useSessionStore(topicSelectors.currentTopics, isEqual);
14
16
  const { isDarkMode } = useThemeMode();
15
17
  const [activeTopicId] = useSessionStore((s) => [s.activeTopicId]);
@@ -20,8 +22,10 @@ export const Topic = () => {
20
22
  s.updateGuideState,
21
23
  ]);
22
24
 
23
- return (
24
- <Flexbox gap={2}>
25
+ return !hydrated ? (
26
+ <SkeletonList />
27
+ ) : (
28
+ <Flexbox gap={2} style={{ marginBottom: 12 }}>
25
29
  {topics?.length === 0 && (
26
30
  <Empty
27
31
  alt={t('topic.desc')}
@@ -1,15 +1,22 @@
1
- import { DraggablePanel, DraggablePanelContainer } from '@lobehub/ui';
1
+ import { DraggablePanel, SearchBar } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
3
  import { rgba } from 'polished';
4
4
  import { memo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { Flexbox } from 'react-layout-kit';
5
7
 
6
8
  import HeaderSpacing from '@/components/HeaderSpacing';
7
9
  import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
8
10
  import { useGlobalStore } from '@/store/global';
9
11
 
10
- import Inner from './Inner';
12
+ import SystemRole from './SystemRole';
13
+ import { Topic } from './Topic';
11
14
 
12
15
  const useStyles = createStyles(({ cx, css, token, stylish }) => ({
16
+ content: css`
17
+ display: flex;
18
+ flex-direction: column;
19
+ `,
13
20
  drawer: cx(
14
21
  stylish.blurStrong,
15
22
  css`
@@ -31,18 +38,29 @@ const SideBar = memo<SideBarProps>(({ systemRole = true }) => {
31
38
  s.toggleChatSideBar,
32
39
  ]);
33
40
 
41
+ const { t } = useTranslation('common');
42
+
34
43
  return (
35
44
  <DraggablePanel
36
45
  className={styles.drawer}
46
+ classNames={{
47
+ content: styles.content,
48
+ }}
37
49
  expand={showAgentSettings}
38
50
  minWidth={CHAT_SIDEBAR_WIDTH}
39
51
  onExpandChange={toggleConfig}
40
52
  placement={'right'}
41
53
  >
42
54
  <HeaderSpacing />
43
- <DraggablePanelContainer style={{ flex: 'none', minWidth: CHAT_SIDEBAR_WIDTH }}>
44
- <Inner systemRole={systemRole} />
45
- </DraggablePanelContainer>
55
+ {systemRole && <SystemRole />}
56
+ <Flexbox height={'100%'} style={{ overflow: 'hidden' }}>
57
+ <Flexbox padding={16}>
58
+ <SearchBar placeholder={t('topic.searchPlaceholder')} spotlight type={'ghost'} />
59
+ </Flexbox>
60
+ <Flexbox gap={16} paddingInline={16} style={{ overflowY: 'auto', position: 'relative' }}>
61
+ <Topic />
62
+ </Flexbox>
63
+ </Flexbox>
46
64
  </DraggablePanel>
47
65
  );
48
66
  });
@@ -223,7 +223,10 @@ export const chatMessage: StateCreator<
223
223
  const chats = chatSelectors.currentChats(get());
224
224
 
225
225
  const currentIndex = chats.findIndex((c) => c.id === messageId);
226
+ if (currentIndex < 0) return;
227
+
226
228
  const currentMessage = chats[currentIndex];
229
+
227
230
  let contextMessages: ChatMessage[] = [];
228
231
 
229
232
  switch (currentMessage.role) {
@@ -15,15 +15,18 @@ export const getChatsById =
15
15
 
16
16
  if (!session) return [];
17
17
 
18
- return organizeChats(
19
- session,
20
- {
21
- assistant: agentSelectors.currentAgentAvatar(s),
22
- assistantBackground: agentSelectors.currentAgentBackgroundColor(s),
23
- user: useGlobalStore.getState().settings.avatar || DEFAULT_USER_AVATAR,
18
+ return organizeChats(session, {
19
+ meta: {
20
+ assistant: {
21
+ avatar: agentSelectors.currentAgentAvatar(s),
22
+ backgroundColor: agentSelectors.currentAgentBackgroundColor(s),
23
+ },
24
+ user: {
25
+ avatar: useGlobalStore.getState().settings.avatar || DEFAULT_USER_AVATAR,
26
+ },
24
27
  },
25
- s.activeTopicId,
26
- );
28
+ topicId: s.activeTopicId,
29
+ });
27
30
  };
28
31
 
29
32
  // 当前激活的消息列表
@@ -22,5 +22,5 @@ export const getTopicMessages = (topicId: string) => (s: SessionStore) => {
22
22
  const session = sessionSelectors.currentSession(s);
23
23
  if (!session) return [];
24
24
 
25
- return organizeChats(session, { assistant: '', user: '' }, topicId);
25
+ return organizeChats(session, { topicId });
26
26
  };
@@ -52,7 +52,7 @@ beforeEach(() => {
52
52
 
53
53
  describe('organizeChats', () => {
54
54
  it('should return an array of chat messages', () => {
55
- const result = organizeChats(session, { assistant: '', user: '' });
55
+ const result = organizeChats(session);
56
56
  expect(Array.isArray(result)).toBe(true);
57
57
  expect(result.length).toBe(3);
58
58
  expect(result[0].id).toBe('1');
@@ -61,7 +61,7 @@ describe('organizeChats', () => {
61
61
  });
62
62
 
63
63
  it('should sort chat messages in ascending order of createAt', () => {
64
- const result = organizeChats(session, { assistant: '', user: '' });
64
+ const result = organizeChats(session);
65
65
  expect(result[0].id).toBe('1');
66
66
  expect(result[1].id).toBe('2');
67
67
  expect(result[2].id).toBe('3');
@@ -69,7 +69,7 @@ describe('organizeChats', () => {
69
69
 
70
70
  it('should filter out archived messages', () => {
71
71
  session.chats['2'].topicId = '123';
72
- const result = organizeChats(session, { assistant: '', user: '' });
72
+ const result = organizeChats(session);
73
73
  expect(result.length).toBe(2);
74
74
  expect(result[0].id).toBe('1');
75
75
  expect(result[1].id).toBe('3');
@@ -82,8 +82,10 @@ describe('organizeChats', () => {
82
82
  };
83
83
 
84
84
  const result = organizeChats(session, {
85
- assistant: avatar,
86
- user: settings.avatar,
85
+ meta: {
86
+ user: { avatar: settings.avatar },
87
+ assistant: { avatar },
88
+ },
87
89
  });
88
90
 
89
91
  expect(result[0].meta.avatar).toBe(avatar);
@@ -94,7 +96,7 @@ describe('organizeChats', () => {
94
96
  it('should reorder messages based on parent-child relationship', () => {
95
97
  session.chats['2'].parentId = '1';
96
98
  session.chats['3'].parentId = '2';
97
- const result = organizeChats(session, { assistant: '', user: '' });
99
+ const result = organizeChats(session);
98
100
  expect(result.length).toBe(3);
99
101
  expect(result[0].id).toBe('1');
100
102
  expect(result[1].id).toBe('2');
@@ -105,7 +107,7 @@ describe('organizeChats', () => {
105
107
  session.chats['2'].parentId = '1';
106
108
  session.chats['3'].parentId = '2';
107
109
  session.chats['3'].id = '2';
108
- const result = organizeChats(session, { assistant: '', user: '' });
110
+ const result = organizeChats(session);
109
111
  expect(result.length).toBe(2);
110
112
  expect(result[0].id).toBe('1');
111
113
  expect(result[1].id).toBe('2');
@@ -117,7 +119,7 @@ describe('organizeChats', () => {
117
119
  config: {},
118
120
  type: 'agent',
119
121
  } as LobeAgentSession;
120
- const result = organizeChats(emptySession, { assistant: '', user: '' });
122
+ const result = organizeChats(emptySession);
121
123
  expect(Array.isArray(result)).toBe(true);
122
124
  expect(result.length).toBe(0);
123
125
  });
@@ -143,7 +145,7 @@ describe('organizeChats', () => {
143
145
  };
144
146
  }
145
147
 
146
- const result = organizeChats(largeSession, { assistant: '', user: '' });
148
+ const result = organizeChats(largeSession);
147
149
  expect(result.length).toBe(numMessages);
148
150
  expect(result[0].id).toBe('1');
149
151
  expect(result[numMessages - 1].id).toBe(numMessages.toString());
@@ -222,7 +224,7 @@ describe('organizeChats', () => {
222
224
  updateAt: 1690110700808,
223
225
  } as LobeAgentSession;
224
226
 
225
- const result = organizeChats(realSession, { assistant: '', user: '' });
227
+ const result = organizeChats(realSession);
226
228
 
227
229
  expect(
228
230
  result.map((i) => ({ id: i.id, content: i.content, role: i.role, createAt: i.createAt })),
@@ -263,13 +265,15 @@ describe('organizeChats', () => {
263
265
  ]);
264
266
  });
265
267
 
266
- const avatar = {
267
- assistant: 'assistant-avatar',
268
- user: 'user-avatar',
268
+ const params = {
269
+ meta: {
270
+ user: { avatar: 'user-avatar' },
271
+ assistant: { avatar: 'assistant-avatar' },
272
+ },
269
273
  };
270
274
 
271
275
  it('should organize chats in chronological order when topicId is not provided', () => {
272
- const result = organizeChats(session, avatar);
276
+ const result = organizeChats(session, params);
273
277
 
274
278
  expect(result.length).toBe(3);
275
279
  expect(result[0].id).toBe('1');
@@ -278,21 +282,21 @@ describe('organizeChats', () => {
278
282
  });
279
283
 
280
284
  it('should only return chats with specified topicId when topicId is provided', () => {
281
- const result = organizeChats(session, avatar, 'topic-id');
285
+ const result = organizeChats(session, { ...params, topicId: 'topic-id' });
282
286
 
283
287
  expect(result.length).toBe(0);
284
288
  });
285
289
 
286
290
  describe('user Meta', () => {
287
291
  it('should return correct meta for user role', () => {
288
- const result = organizeChats(session, avatar);
292
+ const result = organizeChats(session, params);
289
293
  const meta = result[1].meta;
290
294
 
291
- expect(meta.avatar).toBe(avatar.user);
295
+ expect(meta.avatar).toBe(params.meta.user.avatar);
292
296
  });
293
297
 
294
298
  it('should return correct meta for assistant role', () => {
295
- const result = organizeChats(session, avatar);
299
+ const result = organizeChats(session, params);
296
300
  const meta = result[0].meta;
297
301
 
298
302
  expect(meta.avatar).toBe('assistant-avatar');
@@ -313,7 +317,7 @@ describe('organizeChats', () => {
313
317
 
314
318
  session.chats[message.id] = message;
315
319
 
316
- const result = organizeChats(session, avatar);
320
+ const result = organizeChats(session, params);
317
321
  const meta = result[3].meta;
318
322
 
319
323
  expect(meta.avatar).toBe('🧩');
@@ -334,7 +338,7 @@ describe('organizeChats', () => {
334
338
 
335
339
  session.chats[message.id] = message;
336
340
 
337
- const result = organizeChats(session, avatar);
341
+ const result = organizeChats(session, params);
338
342
  const meta = result[3].meta;
339
343
 
340
344
  expect(meta.avatar).toBe('🧩');
@@ -1,17 +1,25 @@
1
1
  import { PluginsMap } from '@/plugins';
2
2
  import { ChatMessage } from '@/types/chatMessage';
3
+ import { MetaData } from '@/types/meta';
3
4
  import { LobeAgentSession } from '@/types/session';
4
5
 
6
+ interface OrganizeParams {
7
+ meta?: {
8
+ assistant?: MetaData;
9
+ user?: MetaData;
10
+ };
11
+ topicId?: string;
12
+ }
13
+
5
14
  export const organizeChats = (
6
15
  session: LobeAgentSession,
7
- avatar: { assistant: string; assistantBackground?: string; user: string },
8
- topicId?: string,
16
+ { topicId, meta }: OrganizeParams = {},
9
17
  ) => {
10
18
  const getMeta = (message: ChatMessage) => {
11
19
  switch (message.role) {
12
20
  case 'user': {
13
21
  return {
14
- avatar: avatar.user,
22
+ avatar: meta?.user?.avatar,
15
23
  };
16
24
  }
17
25
 
@@ -21,9 +29,9 @@ export const organizeChats = (
21
29
 
22
30
  case 'assistant': {
23
31
  return {
24
- avatar: avatar.assistant,
25
- backgroundColor: avatar.assistantBackground,
26
- title: session.meta.title,
32
+ avatar: meta?.assistant?.avatar,
33
+ backgroundColor: meta?.assistant?.backgroundColor,
34
+ title: meta?.assistant?.title || session.meta.title,
27
35
  };
28
36
  }
29
37
 
@@ -1,42 +0,0 @@
1
- import { DraggablePanelBody, SearchBar } from '@lobehub/ui';
2
- import { Skeleton } from 'antd';
3
- import { memo } from 'react';
4
- import { useTranslation } from 'react-i18next';
5
- import { Flexbox } from 'react-layout-kit';
6
-
7
- import { useSessionHydrated } from '@/store/session';
8
-
9
- import SystemRole from './SystemRole';
10
- import { Topic } from './Topic';
11
-
12
- const Inner = memo<{ systemRole: boolean }>(({ systemRole }) => {
13
- const hydrated = useSessionHydrated();
14
- const { t } = useTranslation('common');
15
-
16
- return (
17
- <DraggablePanelBody style={{ padding: 0 }}>
18
- {systemRole && <SystemRole />}
19
- <Flexbox gap={16} padding={16}>
20
- <SearchBar placeholder={t('topic.searchPlaceholder')} spotlight type={'ghost'} />
21
- {!hydrated ? (
22
- <Flexbox gap={8} style={{ marginTop: 8 }}>
23
- {Array.from({ length: 8 }).map((_, i) => (
24
- <Skeleton
25
- active
26
- avatar={false}
27
- key={i}
28
- paragraph={{ rows: 1, width: '100%' }}
29
- round
30
- title={false}
31
- />
32
- ))}
33
- </Flexbox>
34
- ) : (
35
- <Topic />
36
- )}
37
- </Flexbox>
38
- </DraggablePanelBody>
39
- );
40
- });
41
-
42
- export default Inner;