@lobehub/chat 0.148.7 → 0.148.9

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/package.json +2 -2
  3. package/src/app/api/chat/google/route.test.ts +2 -1
  4. package/src/app/api/chat/google/route.ts +20 -2
  5. package/src/app/chat/features/SessionListContent/CollapseGroup/Actions.tsx +11 -5
  6. package/src/app/chat/features/SessionListContent/DefaultMode.tsx +6 -4
  7. package/src/app/chat/features/SessionListContent/List/AddButton.tsx +4 -9
  8. package/src/app/chat/features/SessionListContent/Modals/ConfigGroupModal/GroupItem.tsx +21 -16
  9. package/src/app/chat/features/SessionListContent/Modals/ConfigGroupModal/index.tsx +8 -2
  10. package/src/app/chat/features/SessionListContent/Modals/CreateGroupModal.tsx +9 -1
  11. package/src/app/chat/features/SessionListContent/Modals/RenameGroupModal.tsx +12 -3
  12. package/src/app/home/Redirect.tsx +2 -2
  13. package/src/app/welcome/(desktop)/features/Footer.tsx +1 -1
  14. package/src/app/welcome/features/Banner/index.tsx +5 -9
  15. package/src/database/client/models/__tests__/session.test.ts +2 -2
  16. package/src/database/client/models/session.ts +4 -14
  17. package/src/locales/default/chat.ts +6 -2
  18. package/src/locales/default/welcome.ts +1 -0
  19. package/src/services/config.ts +5 -21
  20. package/src/services/message/client.ts +10 -0
  21. package/src/services/message/index.ts +1 -13
  22. package/src/services/message/type.ts +3 -0
  23. package/src/services/session/client.ts +3 -0
  24. package/src/services/session/type.ts +8 -2
  25. package/src/services/topic/client.ts +1 -1
  26. package/src/services/topic/type.ts +3 -2
  27. package/src/store/session/slices/session/action.ts +74 -76
  28. package/src/store/session/slices/session/initialState.ts +8 -1
  29. package/src/store/session/slices/session/reducers.test.ts +79 -0
  30. package/src/store/session/slices/session/reducers.ts +61 -0
  31. package/src/store/session/slices/sessionGroup/action.test.ts +9 -0
  32. package/src/store/session/slices/sessionGroup/action.ts +25 -6
  33. package/src/store/session/slices/sessionGroup/reducer.test.ts +86 -0
  34. package/src/store/session/slices/sessionGroup/reducer.ts +56 -0
  35. package/src/store/session/slices/sessionGroup/selectors.ts +1 -5
  36. package/src/types/service.ts +7 -0
  37. package/src/types/session.ts +5 -7
  38. package/src/utils/uuid.ts +4 -4
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.148.9](https://github.com/lobehub/lobe-chat/compare/v0.148.8...v0.148.9)
6
+
7
+ <sup>Released on **2024-04-23**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Refactor for session server mode.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Refactor for session server mode, closes [#2163](https://github.com/lobehub/lobe-chat/issues/2163) ([e012597](https://github.com/lobehub/lobe-chat/commit/e012597))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ### [Version 0.148.8](https://github.com/lobehub/lobe-chat/compare/v0.148.7...v0.148.8)
31
+
32
+ <sup>Released on **2024-04-23**</sup>
33
+
34
+ #### 💄 Styles
35
+
36
+ - **misc**: update some `gemini` deployment restrictions.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### Styles
44
+
45
+ - **misc**: update some `gemini` deployment restrictions, closes [#2149](https://github.com/lobehub/lobe-chat/issues/2149) ([6d36863](https://github.com/lobehub/lobe-chat/commit/6d36863))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ### [Version 0.148.7](https://github.com/lobehub/lobe-chat/compare/v0.148.6...v0.148.7)
6
56
 
7
57
  <sup>Released on **2024-04-23**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.148.7",
3
+ "version": "0.148.9",
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",
@@ -173,7 +173,7 @@
173
173
  "@next/eslint-plugin-next": "^14.2.2",
174
174
  "@peculiar/webcrypto": "^1.4.6",
175
175
  "@testing-library/jest-dom": "^6.4.2",
176
- "@testing-library/react": "^15.0.2",
176
+ "@testing-library/react": "^15.0.4",
177
177
  "@types/chroma-js": "^2.4.4",
178
178
  "@types/debug": "^4.1.12",
179
179
  "@types/diff": "^5.2.0",
@@ -15,7 +15,8 @@ describe('Configuration tests', () => {
15
15
  });
16
16
 
17
17
  it('should contain specific regions in preferredRegion', () => {
18
- expect(preferredRegion).not.contain(['hk1']);
18
+ expect(preferredRegion).not.contain(['hkg1']);
19
+ expect(preferredRegion).not.contain(['dub1']);
19
20
  });
20
21
  });
21
22
 
@@ -13,7 +13,25 @@ import { POST as UniverseRoute } from '../[provider]/route';
13
13
  // so if you want to use with proxy, you need comment the code below
14
14
  export const runtime = 'edge';
15
15
 
16
- // due to gemini-1.5-pro only can be used in us, so we need to set the preferred region only in US
17
- export const preferredRegion = ['cle1', 'iad1', 'pdx1', 'sfo1'];
16
+ // due to Gemini-1.5-pro is not available in Hong Kong and Ireland, we need to set the preferred region to exclude "Hong Kong" or "Ireland".
17
+ // refs: https://github.com/lobehub/lobe-chat/pull/2149
18
+ export const preferredRegion = [
19
+ 'icn1',
20
+ 'sin1',
21
+ 'hnd1',
22
+ 'kix1',
23
+ 'bom1',
24
+ 'cdg1',
25
+ 'lhr1',
26
+ 'cpt1',
27
+ 'pdx1',
28
+ 'arn1',
29
+ 'cle1',
30
+ 'syd1',
31
+ 'iad1',
32
+ 'fra1',
33
+ 'sfo1',
34
+ 'gru1'
35
+ ];
18
36
 
19
37
  export const POST = async (req: Request) => UniverseRoute(req, { params: { provider: 'google' } });
@@ -27,7 +27,7 @@ const Actions = memo<ActionsProps>(
27
27
  ({ id, openRenameModal, openConfigModal, onOpenChange, isCustomGroup, isPinned }) => {
28
28
  const { t } = useTranslation('chat');
29
29
  const { styles } = useStyles();
30
- const { modal } = App.useApp();
30
+ const { modal, message } = App.useApp();
31
31
 
32
32
  const [createSession, removeSessionGroup] = useSessionStore((s) => [
33
33
  s.createSession,
@@ -48,9 +48,15 @@ const Actions = memo<ActionsProps>(
48
48
  icon: <Icon icon={Plus} />,
49
49
  key: 'newAgent',
50
50
  label: t('newAgent'),
51
- onClick: ({ domEvent }) => {
51
+ onClick: async ({ domEvent }) => {
52
52
  domEvent.stopPropagation();
53
- createSession({ group: id, pinned: isPinned });
53
+ const key = 'createNewAgentInGroup';
54
+ message.loading({ content: t('sessionGroup.creatingAgent'), duration: 0, key });
55
+
56
+ await createSession({ group: id, pinned: isPinned });
57
+
58
+ message.destroy(key);
59
+ message.success({ content: t('sessionGroup.createAgentSuccess') });
54
60
  },
55
61
  };
56
62
 
@@ -83,9 +89,9 @@ const Actions = memo<ActionsProps>(
83
89
  modal.confirm({
84
90
  centered: true,
85
91
  okButtonProps: { danger: true },
86
- onOk: () => {
92
+ onOk: async () => {
87
93
  if (!id) return;
88
- removeSessionGroup(id);
94
+ await removeSessionGroup(id);
89
95
  },
90
96
  rootClassName: styles.modalRoot,
91
97
  title: t('sessionGroup.confirmRemoveGroupAlert'),
@@ -1,10 +1,12 @@
1
1
  import { CollapseProps } from 'antd';
2
+ import isEqual from 'fast-deep-equal';
2
3
  import { memo, useMemo, useState } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
4
5
 
5
6
  import { useGlobalStore } from '@/store/global';
6
7
  import { preferenceSelectors } from '@/store/global/selectors';
7
8
  import { useSessionStore } from '@/store/session';
9
+ import { sessionSelectors } from '@/store/session/selectors';
8
10
  import { SessionDefaultGroup } from '@/types/session';
9
11
 
10
12
  import Actions from '../SessionListContent/CollapseGroup/Actions';
@@ -22,11 +24,11 @@ const SessionListContent = memo(() => {
22
24
  const [configGroupModalOpen, setConfigGroupModalOpen] = useState(false);
23
25
 
24
26
  const [useFetchSessions] = useSessionStore((s) => [s.useFetchSessions]);
25
- const { data } = useFetchSessions();
27
+ useFetchSessions();
26
28
 
27
- const pinnedSessions = data?.pinned;
28
- const defaultSessions = data?.default;
29
- const customSessionGroups = data?.customGroup;
29
+ const defaultSessions = useSessionStore(sessionSelectors.defaultSessions, isEqual);
30
+ const customSessionGroups = useSessionStore(sessionSelectors.customSessionGroups, isEqual);
31
+ const pinnedSessions = useSessionStore(sessionSelectors.pinnedSessions, isEqual);
30
32
 
31
33
  const [sessionGroupKeys, updatePreference] = useGlobalStore((s) => [
32
34
  preferenceSelectors.sessionGroupKeys(s),
@@ -12,18 +12,13 @@ const AddButton = memo<{ groupId?: string }>(({ groupId }) => {
12
12
  const { t } = useTranslation('chat');
13
13
  const createSession = useSessionStore((s) => s.createSession);
14
14
 
15
- const { mutate, isValidating } = useActionSWR('session.createSession', (groupId) =>
16
- createSession({ group: groupId }),
17
- );
15
+ const { mutate, isValidating } = useActionSWR(['session.createSession', groupId], () => {
16
+ return createSession({ group: groupId });
17
+ });
18
18
 
19
19
  return (
20
20
  <Flexbox style={{ margin: '12px 16px' }}>
21
- <Button
22
- block
23
- icon={<Icon icon={Plus} />}
24
- loading={isValidating}
25
- onClick={() => mutate(groupId)}
26
- >
21
+ <Button block icon={<Icon icon={Plus} />} loading={isValidating} onClick={() => mutate()}>
27
22
  {t('newAgent')}
28
23
  </Button>
29
24
  </Flexbox>
@@ -1,5 +1,5 @@
1
1
  import { ActionIcon, EditableText, SortableList } from '@lobehub/ui';
2
- import { App, Popconfirm } from 'antd';
2
+ import { App } from 'antd';
3
3
  import { createStyles } from 'antd-style';
4
4
  import { PencilLine, Trash } from 'lucide-react';
5
5
  import { memo, useState } from 'react';
@@ -25,7 +25,7 @@ const useStyles = createStyles(({ css }) => ({
25
25
  const GroupItem = memo<SessionGroupItem>(({ id, name }) => {
26
26
  const { t } = useTranslation('chat');
27
27
  const { styles } = useStyles();
28
- const { message } = App.useApp();
28
+ const { message, modal } = App.useApp();
29
29
 
30
30
  const [editing, setEditing] = useState(false);
31
31
  const [updateSessionGroupName, removeSessionGroup] = useSessionStore((s) => [
@@ -40,29 +40,34 @@ const GroupItem = memo<SessionGroupItem>(({ id, name }) => {
40
40
  <>
41
41
  <span className={styles.title}>{name}</span>
42
42
  <ActionIcon icon={PencilLine} onClick={() => setEditing(true)} size={'small'} />
43
- <Popconfirm
44
- arrow={false}
45
- okButtonProps={{
46
- danger: true,
47
- type: 'primary',
43
+ <ActionIcon
44
+ icon={Trash}
45
+ onClick={() => {
46
+ modal.confirm({
47
+ centered: true,
48
+ okButtonProps: {
49
+ danger: true,
50
+ type: 'primary',
51
+ },
52
+ onOk: async () => {
53
+ await removeSessionGroup(id);
54
+ },
55
+ title: t('sessionGroup.confirmRemoveGroupAlert'),
56
+ });
48
57
  }}
49
- onConfirm={() => {
50
- removeSessionGroup(id);
51
- }}
52
- title={t('sessionGroup.confirmRemoveGroupAlert')}
53
- >
54
- <ActionIcon icon={Trash} size={'small'} />
55
- </Popconfirm>
58
+ size={'small'}
59
+ />
56
60
  </>
57
61
  ) : (
58
62
  <EditableText
59
63
  editing={editing}
60
- onChangeEnd={(input) => {
64
+ onChangeEnd={async (input) => {
61
65
  if (name !== input) {
62
66
  if (!input) return;
63
67
  if (input.length === 0 || input.length > 20)
64
68
  return message.warning(t('sessionGroup.tooLong'));
65
- updateSessionGroupName(id, input);
69
+
70
+ await updateSessionGroupName(id, input);
66
71
  message.success(t('sessionGroup.renameSuccess'));
67
72
  }
68
73
  setEditing(false);
@@ -3,7 +3,7 @@ import { Button } from 'antd';
3
3
  import { createStyles } from 'antd-style';
4
4
  import isEqual from 'fast-deep-equal';
5
5
  import { Plus } from 'lucide-react';
6
- import { memo } from 'react';
6
+ import { memo, useState } from 'react';
7
7
  import { useTranslation } from 'react-i18next';
8
8
  import { Flexbox } from 'react-layout-kit';
9
9
 
@@ -35,6 +35,7 @@ const ConfigGroupModal = memo<ModalProps>(({ open, onCancel }) => {
35
35
  s.addSessionGroup,
36
36
  s.updateSessionGroupSort,
37
37
  ]);
38
+ const [loading, setLoading] = useState(false);
38
39
 
39
40
  return (
40
41
  <Modal
@@ -67,7 +68,12 @@ const ConfigGroupModal = memo<ModalProps>(({ open, onCancel }) => {
67
68
  <Button
68
69
  block
69
70
  icon={<Icon icon={Plus} />}
70
- onClick={() => addSessionGroup(t('sessionGroup.newGroup'))}
71
+ loading={loading}
72
+ onClick={async () => {
73
+ setLoading(true);
74
+ await addSessionGroup(t('sessionGroup.newGroup'));
75
+ setLoading(false);
76
+ }}
71
77
  >
72
78
  {t('sessionGroup.createGroup')}
73
79
  </Button>
@@ -22,21 +22,29 @@ const CreateGroupModal = memo<CreateGroupModalProps>(
22
22
  s.addSessionGroup,
23
23
  ]);
24
24
  const [input, setInput] = useState('');
25
+ const [loading, setLoading] = useState(false);
25
26
 
26
27
  return (
27
28
  <div onClick={(e) => e.stopPropagation()}>
28
29
  <Modal
29
30
  allowFullscreen
30
- onCancel={onCancel}
31
+ destroyOnClose
32
+ okButtonProps={{ loading }}
33
+ onCancel={(e) => {
34
+ setInput('');
35
+ onCancel?.(e);
36
+ }}
31
37
  onOk={async (e: MouseEvent<HTMLButtonElement>) => {
32
38
  if (!input) return;
33
39
 
34
40
  if (input.length === 0 || input.length > 20)
35
41
  return message.warning(t('sessionGroup.tooLong'));
36
42
 
43
+ setLoading(true);
37
44
  const groupId = await addCustomGroup(input);
38
45
  await updateSessionGroup(id, groupId);
39
46
  toggleExpandSessionGroup(groupId, true);
47
+ setLoading(false);
40
48
 
41
49
  message.success(t('sessionGroup.createSuccess'));
42
50
  onCancel?.(e);
@@ -18,18 +18,27 @@ const RenameGroupModal = memo<RenameGroupModalProps>(({ id, open, onCancel }) =>
18
18
  const group = useSessionStore((s) => sessionGroupSelectors.getGroupById(id)(s), isEqual);
19
19
 
20
20
  const [input, setInput] = useState<string>();
21
+ const [loading, setLoading] = useState(false);
21
22
 
22
23
  const { message } = App.useApp();
23
24
  return (
24
25
  <Modal
25
26
  allowFullscreen
26
- onCancel={onCancel}
27
- onOk={(e) => {
27
+ destroyOnClose
28
+ okButtonProps={{ loading }}
29
+ onCancel={(e) => {
30
+ setInput(group?.name);
31
+ onCancel?.(e);
32
+ }}
33
+ onOk={async (e) => {
28
34
  if (!input) return;
29
35
  if (input.length === 0 || input.length > 20)
30
36
  return message.warning(t('sessionGroup.tooLong'));
31
- updateSessionGroupName(id, input);
37
+ setLoading(true);
38
+ await updateSessionGroupName(id, input);
32
39
  message.success(t('sessionGroup.renameSuccess'));
40
+ setLoading(false);
41
+
33
42
  onCancel?.(e);
34
43
  }}
35
44
  open={open}
@@ -8,8 +8,8 @@ import { sessionService } from '@/services/session';
8
8
 
9
9
  const checkHasConversation = async () => {
10
10
  const hasMessages = await messageService.hasMessages();
11
- const hasAgents = await sessionService.countSessions();
12
- return hasMessages || hasAgents === 0;
11
+ const hasAgents = await sessionService.hasSessions();
12
+ return hasMessages || hasAgents;
13
13
  };
14
14
 
15
15
  const Redirect = memo(() => {
@@ -16,7 +16,7 @@ const Footer = memo(() => {
16
16
  return (
17
17
  <Flexbox align={'center'} horizontal justify={'space-between'} style={{ padding: 16 }}>
18
18
  <span style={{ color: theme.colorTextDescription }}>
19
- ©{new Date().getFullYear()} LobeHub
19
+ © 2023 - {new Date().getFullYear()} LobeHub, LLC
20
20
  </span>
21
21
  <Flexbox horizontal>
22
22
  <ActionIcon
@@ -3,12 +3,12 @@
3
3
  import { Icon } from '@lobehub/ui';
4
4
  import { Button } from 'antd';
5
5
  import { SendHorizonal } from 'lucide-react';
6
+ import Link from 'next/link';
6
7
  import { useRouter } from 'next/navigation';
7
8
  import { memo } from 'react';
8
9
  import { useTranslation } from 'react-i18next';
9
10
  import { Flexbox } from 'react-layout-kit';
10
11
 
11
- import DataImporter from '@/features/DataImporter';
12
12
  import { useGlobalStore } from '@/store/global';
13
13
 
14
14
  import Hero from './Hero';
@@ -32,15 +32,11 @@ const Banner = memo<{ mobile?: boolean }>(({ mobile }) => {
32
32
  justify={'center'}
33
33
  width={'100%'}
34
34
  >
35
- <DataImporter
36
- onFinishImport={() => {
37
- router.push('/chat');
38
- }}
39
- >
40
- <Button block={mobile} size={'large'}>
41
- {t('button.import')}
35
+ <Link href={'/market'}>
36
+ <Button block={mobile} size={'large'} type={'default'}>
37
+ {t('button.market')}
42
38
  </Button>
43
- </DataImporter>
39
+ </Link>
44
40
  <Button
45
41
  block={mobile}
46
42
  onClick={() => (isMobile ? router.push('/chat') : switchBackToChat())}
@@ -179,8 +179,8 @@ describe('SessionModel', () => {
179
179
  await SessionModel.create('agent', sessionData);
180
180
 
181
181
  const sessionsWithGroups = await SessionModel.queryWithGroups();
182
- expect(sessionsWithGroups.all).toHaveLength(1);
183
- expect(sessionsWithGroups.all[0]).toEqual(expect.objectContaining(sessionData));
182
+ expect(sessionsWithGroups.sessions).toHaveLength(1);
183
+ expect(sessionsWithGroups.sessions[0]).toEqual(expect.objectContaining(sessionData));
184
184
  });
185
185
  });
186
186
 
@@ -43,21 +43,11 @@ class _SessionModel extends BaseModel {
43
43
  }
44
44
 
45
45
  async queryWithGroups(): Promise<ChatSessionList> {
46
- const groups = await SessionGroupModel.query();
47
- const customGroups = await this.queryByGroupIds(groups.map((item) => item.id));
48
- const defaultItems = await this.querySessionsByGroupId(SessionDefaultGroup.Default);
49
- const pinnedItems = await this.getPinnedSessions();
46
+ const sessionGroups = await SessionGroupModel.query();
50
47
 
51
- const all = await this.query();
52
- return {
53
- all,
54
- customGroup: groups.map((group) => ({
55
- ...group,
56
- children: customGroups[group.id],
57
- })),
58
- default: defaultItems,
59
- pinned: pinnedItems,
60
- };
48
+ const sessions = await this.query();
49
+
50
+ return { sessionGroups, sessions };
61
51
  }
62
52
 
63
53
  /**
@@ -50,13 +50,17 @@ export default {
50
50
  sessionGroup: {
51
51
  config: '分组管理',
52
52
  confirmRemoveGroupAlert: '即将删除该分组,删除后该分组的助手将移动到默认列表,请确认你的操作',
53
+ createAgentSuccess: '助手创建成功',
53
54
  createGroup: '添加新分组',
54
- createSuccess: '创建成功',
55
+ createSuccess: '分组创建成功',
56
+ creatingAgent: '助手创建中...',
55
57
  inputPlaceholder: '请输入分组名称...',
56
58
  moveGroup: '移动到分组',
57
59
  newGroup: '新分组',
58
60
  rename: '重命名分组',
59
61
  renameSuccess: '重命名成功',
62
+ sortSuccess: '重新排序成功',
63
+ sorting: '分组排序更新中...',
60
64
  tooLong: '分组名称长度需在 1-20 之内',
61
65
  },
62
66
  shareModal: {
@@ -126,6 +130,6 @@ export default {
126
130
  dragDesc: '拖拽文件到这里,支持上传多个图片。按住 Shift 直接发送图片',
127
131
  dragFileDesc: '拖拽图片和文件到这里,支持上传多个图片和文件。按住 Shift 直接发送图片或文件',
128
132
  dragFileTitle: '上传文件',
129
- dragTitle: '上传图片'
133
+ dragTitle: '上传图片',
130
134
  },
131
135
  };
@@ -1,6 +1,7 @@
1
1
  export default {
2
2
  button: {
3
3
  import: '导入配置',
4
+ market: '逛逛市场',
4
5
  start: '立即开始',
5
6
  },
6
7
  header: '欢迎使用',
@@ -65,31 +65,15 @@ class ConfigService {
65
65
 
66
66
  case 'all': {
67
67
  await this.importSettings(config.state.settings);
68
-
69
- const sessionGroups = await this.importSessionGroups(config.state.sessionGroups);
70
-
71
- const [sessions, messages, topics] = await Promise.all([
72
- this.importSessions(config.state.sessions),
73
- this.importMessages(config.state.messages),
74
- this.importTopics(config.state.topics),
75
- ]);
76
-
77
- return {
78
- messages: this.mapImportResult(messages),
79
- sessionGroups: this.mapImportResult(sessionGroups),
80
- sessions: this.mapImportResult(sessions),
81
- topics: this.mapImportResult(topics),
82
- };
83
68
  }
69
+ // all and sessions have the same data process, so we can fall through
84
70
 
71
+ // eslint-disable-next-line no-fallthrough
85
72
  case 'sessions': {
86
73
  const sessionGroups = await this.importSessionGroups(config.state.sessionGroups);
87
-
88
- const [sessions, messages, topics] = await Promise.all([
89
- this.importSessions(config.state.sessions),
90
- this.importMessages(config.state.messages),
91
- this.importTopics(config.state.topics),
92
- ]);
74
+ const sessions = await this.importSessions(config.state.sessions);
75
+ const topics = await this.importTopics(config.state.topics);
76
+ const messages = await this.importMessages(config.state.messages);
93
77
 
94
78
  return {
95
79
  messages: this.mapImportResult(messages),
@@ -62,4 +62,14 @@ export class ClientService implements IMessageService {
62
62
  async removeAllMessages() {
63
63
  return MessageModel.clearTable();
64
64
  }
65
+
66
+ async hasMessages() {
67
+ const number = await this.countMessages();
68
+ return number > 0;
69
+ }
70
+
71
+ async messageCountToCheckTrace() {
72
+ const number = await this.countMessages();
73
+ return number >= 4;
74
+ }
65
75
  }
@@ -9,16 +9,4 @@ import { ClientService } from './client';
9
9
 
10
10
  export type { CreateMessageParams } from './type';
11
11
 
12
- class MessageService extends ClientService {
13
- async hasMessages() {
14
- const number = await this.countMessages();
15
- return number > 0;
16
- }
17
-
18
- async messageCountToCheckTrace() {
19
- const number = await this.countMessages();
20
- return number >= 4;
21
- }
22
- }
23
-
24
- export const messageService = new MessageService();
12
+ export const messageService = new ClientService();
@@ -30,4 +30,7 @@ export interface IMessageService {
30
30
  removeMessage(id: string): Promise<any>;
31
31
  removeMessages(assistantId: string, topicId?: string): Promise<any>;
32
32
  removeAllMessages(): Promise<any>;
33
+
34
+ hasMessages(): Promise<boolean>;
35
+ messageCountToCheckTrace(): Promise<boolean>;
33
36
  }
@@ -64,6 +64,9 @@ export class ClientService implements ISessionService {
64
64
  async countSessions() {
65
65
  return SessionModel.count();
66
66
  }
67
+ async hasSessions() {
68
+ return (await this.countSessions()) === 0;
69
+ }
67
70
 
68
71
  async searchSessions(keyword: string) {
69
72
  return SessionModel.queryByKeyword(keyword);
@@ -2,11 +2,13 @@
2
2
  import { DeepPartial } from 'utility-types';
3
3
 
4
4
  import { LobeAgentConfig } from '@/types/agent';
5
+ import { BatchTaskResult } from '@/types/service';
5
6
  import {
6
7
  ChatSessionList,
7
8
  LobeAgentSession,
8
9
  LobeSessionType,
9
10
  LobeSessions,
11
+ SessionGroupId,
10
12
  SessionGroupItem,
11
13
  SessionGroups,
12
14
  } from '@/types/session';
@@ -19,9 +21,13 @@ export interface ISessionService {
19
21
  getGroupedSessions(): Promise<ChatSessionList>;
20
22
  getSessionsByType(type: 'agent' | 'group' | 'all'): Promise<LobeSessions>;
21
23
  countSessions(): Promise<number>;
24
+ hasSessions(): Promise<boolean>;
22
25
  searchSessions(keyword: string): Promise<LobeSessions>;
23
26
 
24
- updateSession(id: string, data: Partial<Pick<LobeAgentSession, 'group' | 'meta'>>): Promise<any>;
27
+ updateSession(
28
+ id: string,
29
+ data: Partial<{ group?: SessionGroupId; pinned?: boolean }>,
30
+ ): Promise<any>;
25
31
  updateSessionConfig(id: string, config: DeepPartial<LobeAgentConfig>): Promise<any>;
26
32
 
27
33
  removeSession(id: string): Promise<any>;
@@ -32,7 +38,7 @@ export interface ISessionService {
32
38
  // ************************************** //
33
39
 
34
40
  createSessionGroup(name: string, sort?: number): Promise<string>;
35
- batchCreateSessionGroups(groups: SessionGroups): Promise<any>;
41
+ batchCreateSessionGroups(groups: SessionGroups): Promise<BatchTaskResult>;
36
42
 
37
43
  getSessionGroups(): Promise<SessionGroupItem[]>;
38
44
 
@@ -5,7 +5,7 @@ import { CreateTopicParams, ITopicService, QueryTopicParams } from './type';
5
5
 
6
6
  export class ClientService implements ITopicService {
7
7
  async createTopic(params: CreateTopicParams): Promise<string> {
8
- const item = await TopicModel.create(params);
8
+ const item = await TopicModel.create(params as any);
9
9
 
10
10
  if (!item) {
11
11
  throw new Error('topic create Error');
@@ -1,10 +1,11 @@
1
1
  /* eslint-disable typescript-sort-keys/interface */
2
+ import { BatchTaskResult } from '@/types/service';
2
3
  import { ChatTopic } from '@/types/topic';
3
4
 
4
5
  export interface CreateTopicParams {
5
6
  favorite?: boolean;
6
7
  messages?: string[];
7
- sessionId: string;
8
+ sessionId?: string | null;
8
9
  title: string;
9
10
  }
10
11
 
@@ -16,7 +17,7 @@ export interface QueryTopicParams {
16
17
 
17
18
  export interface ITopicService {
18
19
  createTopic(params: CreateTopicParams): Promise<string>;
19
- batchCreateTopics(importTopics: ChatTopic[]): Promise<any>;
20
+ batchCreateTopics(importTopics: ChatTopic[]): Promise<BatchTaskResult>;
20
21
  cloneTopic(id: string, newTitle?: string): Promise<string>;
21
22
 
22
23
  getTopics(params: QueryTopicParams): Promise<ChatTopic[]>;