@lobehub/chat 1.33.5 → 1.34.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 +25 -0
- package/changelog/v1.json +9 -0
- package/locales/ar/chat.json +7 -0
- package/locales/ar/common.json +2 -0
- package/locales/ar/models.json +24 -0
- package/locales/ar/setting.json +5 -0
- package/locales/ar/thread.json +5 -0
- package/locales/bg-BG/chat.json +7 -0
- package/locales/bg-BG/common.json +2 -0
- package/locales/bg-BG/models.json +24 -0
- package/locales/bg-BG/setting.json +5 -0
- package/locales/bg-BG/thread.json +5 -0
- package/locales/de-DE/chat.json +7 -0
- package/locales/de-DE/common.json +2 -0
- package/locales/de-DE/models.json +24 -0
- package/locales/de-DE/setting.json +5 -0
- package/locales/de-DE/thread.json +5 -0
- package/locales/en-US/chat.json +7 -0
- package/locales/en-US/common.json +2 -0
- package/locales/en-US/models.json +24 -0
- package/locales/en-US/setting.json +5 -0
- package/locales/en-US/thread.json +5 -0
- package/locales/es-ES/chat.json +7 -0
- package/locales/es-ES/common.json +2 -0
- package/locales/es-ES/models.json +24 -0
- package/locales/es-ES/setting.json +5 -0
- package/locales/es-ES/thread.json +5 -0
- package/locales/fa-IR/chat.json +7 -0
- package/locales/fa-IR/common.json +2 -0
- package/locales/fa-IR/models.json +24 -0
- package/locales/fa-IR/setting.json +5 -0
- package/locales/fa-IR/thread.json +5 -0
- package/locales/fr-FR/chat.json +7 -0
- package/locales/fr-FR/common.json +2 -0
- package/locales/fr-FR/models.json +24 -0
- package/locales/fr-FR/setting.json +5 -0
- package/locales/fr-FR/thread.json +5 -0
- package/locales/it-IT/chat.json +7 -0
- package/locales/it-IT/common.json +2 -0
- package/locales/it-IT/models.json +24 -0
- package/locales/it-IT/setting.json +5 -0
- package/locales/it-IT/thread.json +5 -0
- package/locales/ja-JP/chat.json +7 -0
- package/locales/ja-JP/common.json +2 -0
- package/locales/ja-JP/models.json +24 -0
- package/locales/ja-JP/setting.json +5 -0
- package/locales/ja-JP/thread.json +5 -0
- package/locales/ko-KR/chat.json +7 -0
- package/locales/ko-KR/common.json +2 -0
- package/locales/ko-KR/models.json +24 -0
- package/locales/ko-KR/setting.json +5 -0
- package/locales/ko-KR/thread.json +5 -0
- package/locales/nl-NL/chat.json +7 -0
- package/locales/nl-NL/common.json +2 -0
- package/locales/nl-NL/models.json +24 -0
- package/locales/nl-NL/setting.json +5 -0
- package/locales/nl-NL/thread.json +5 -0
- package/locales/pl-PL/chat.json +7 -0
- package/locales/pl-PL/common.json +2 -0
- package/locales/pl-PL/models.json +24 -0
- package/locales/pl-PL/setting.json +5 -0
- package/locales/pl-PL/thread.json +5 -0
- package/locales/pt-BR/chat.json +7 -0
- package/locales/pt-BR/common.json +2 -0
- package/locales/pt-BR/models.json +24 -0
- package/locales/pt-BR/setting.json +5 -0
- package/locales/pt-BR/thread.json +5 -0
- package/locales/ru-RU/chat.json +7 -0
- package/locales/ru-RU/common.json +2 -0
- package/locales/ru-RU/models.json +24 -0
- package/locales/ru-RU/setting.json +5 -0
- package/locales/ru-RU/thread.json +5 -0
- package/locales/tr-TR/chat.json +7 -0
- package/locales/tr-TR/common.json +2 -0
- package/locales/tr-TR/models.json +24 -0
- package/locales/tr-TR/setting.json +5 -0
- package/locales/tr-TR/thread.json +5 -0
- package/locales/vi-VN/chat.json +7 -0
- package/locales/vi-VN/common.json +2 -0
- package/locales/vi-VN/models.json +24 -0
- package/locales/vi-VN/setting.json +5 -0
- package/locales/vi-VN/thread.json +5 -0
- package/locales/zh-CN/chat.json +7 -0
- package/locales/zh-CN/common.json +2 -0
- package/locales/zh-CN/models.json +24 -0
- package/locales/zh-CN/setting.json +5 -0
- package/locales/zh-CN/thread.json +5 -0
- package/locales/zh-TW/chat.json +7 -0
- package/locales/zh-TW/common.json +2 -0
- package/locales/zh-TW/models.json +24 -0
- package/locales/zh-TW/setting.json +5 -0
- package/locales/zh-TW/thread.json +5 -0
- package/package.json +1 -1
- package/src/app/(main)/chat/(workspace)/@conversation/default.tsx +2 -0
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatHydration/index.tsx +11 -2
- package/src/{features → app/(main)/chat/(workspace)/@conversation/features}/ChatInput/Desktop/Footer/index.tsx +7 -9
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatInput/Desktop/index.tsx +7 -2
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/Thread.tsx +62 -0
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/ThreadItem.tsx +68 -0
- package/src/app/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/index.tsx +62 -2
- package/src/app/(main)/chat/(workspace)/@conversation/features/ThreadHydration.tsx +47 -0
- package/src/app/(main)/chat/(workspace)/@portal/_layout/Desktop.tsx +3 -2
- package/src/app/(main)/chat/(workspace)/@portal/_layout/Mobile.tsx +47 -6
- package/src/app/(main)/chat/(workspace)/@topic/features/SkeletonList.tsx +3 -2
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/ByTimeMode/index.tsx +10 -3
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/FlatMode/index.tsx +1 -1
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/ThreadItem/Content.tsx +164 -0
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/ThreadItem/index.tsx +98 -0
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{TopicItem.tsx → TopicItem/index.tsx} +33 -22
- package/src/app/(main)/chat/(workspace)/_layout/Desktop/Portal.tsx +12 -5
- package/src/app/(main)/chat/(workspace)/_layout/Mobile/index.tsx +1 -2
- package/src/const/message.ts +2 -0
- package/src/const/settings/systemAgent.ts +1 -0
- package/src/database/server/migrations/0012_add_thread.sql +39 -0
- package/src/database/server/migrations/meta/0012_snapshot.json +3671 -0
- package/src/database/server/migrations/meta/_journal.json +7 -0
- package/src/database/server/models/_template.ts +2 -2
- package/src/database/server/models/message.ts +1 -0
- package/src/database/server/models/thread.ts +79 -0
- package/src/database/server/schemas/lobechat/message.ts +2 -1
- package/src/database/server/schemas/lobechat/relations.ts +13 -1
- package/src/database/server/schemas/lobechat/topic.ts +30 -1
- package/src/database/server/utils/idGenerator.ts +1 -0
- package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +6 -4
- package/src/features/ChatInput/ActionBar/Token/index.tsx +24 -5
- package/src/features/ChatInput/ActionBar/config.ts +3 -2
- package/src/features/ChatInput/Desktop/index.tsx +15 -7
- package/src/features/ChatInput/Mobile/index.tsx +4 -4
- package/src/features/Conversation/Actions/Assistant.tsx +24 -5
- package/src/features/Conversation/Actions/User.tsx +21 -4
- package/src/features/Conversation/Actions/index.ts +1 -66
- package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/index.tsx +3 -1
- package/src/features/Conversation/Messages/{Tool/index.tsx → Assistant/ToolCallItem/Tool.tsx} +10 -11
- package/src/features/Conversation/Messages/Assistant/ToolCallItem/index.tsx +5 -3
- package/src/features/Conversation/Messages/Assistant/index.tsx +22 -14
- package/src/features/Conversation/Messages/index.ts +0 -2
- package/src/features/Conversation/components/AutoScroll.tsx +1 -1
- package/src/features/Conversation/components/ChatItem/ActionsBar.tsx +79 -5
- package/src/features/Conversation/components/ChatItem/InPortalThreadContext.ts +3 -0
- package/src/features/Conversation/components/ChatItem/index.tsx +16 -5
- package/src/features/Conversation/components/MarkdownElements/LobeArtifact/Render/index.tsx +9 -1
- package/src/features/Conversation/components/ThreadDivider/index.tsx +19 -0
- package/src/features/Conversation/hooks/useChatListActionsBar.tsx +19 -4
- package/src/features/Portal/Thread/Chat/ChatInput/Footer.tsx +90 -0
- package/src/features/Portal/Thread/Chat/ChatInput/TextArea.tsx +30 -0
- package/src/features/Portal/Thread/Chat/ChatInput/index.tsx +66 -0
- package/src/features/Portal/Thread/Chat/ChatInput/useSend.ts +50 -0
- package/src/features/Portal/Thread/Chat/ChatItem.tsx +62 -0
- package/src/features/Portal/Thread/Chat/ChatList.tsx +49 -0
- package/src/features/Portal/Thread/Chat/ThreadDivider/index.tsx +19 -0
- package/src/features/Portal/Thread/Chat/index.tsx +28 -0
- package/src/features/Portal/Thread/Header/Active.tsx +35 -0
- package/src/features/Portal/Thread/Header/New.tsx +37 -0
- package/src/features/Portal/Thread/Header/Title.tsx +18 -0
- package/src/features/Portal/Thread/Header/index.tsx +20 -0
- package/src/features/Portal/Thread/hook.ts +8 -0
- package/src/features/Portal/Thread/index.ts +12 -0
- package/src/features/Portal/router.tsx +2 -1
- package/src/hooks/useFetchTopics.ts +7 -1
- package/src/locales/default/chat.ts +8 -1
- package/src/locales/default/common.ts +3 -0
- package/src/locales/default/index.ts +2 -0
- package/src/locales/default/setting.ts +5 -0
- package/src/locales/default/thread.ts +5 -0
- package/src/server/routers/lambda/index.ts +2 -0
- package/src/server/routers/lambda/thread.ts +83 -0
- package/src/services/thread.ts +54 -0
- package/src/store/chat/initialState.ts +3 -0
- package/src/store/chat/selectors.ts +2 -1
- package/src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts +1 -1
- package/src/store/chat/slices/aiChat/actions/__tests__/rag.test.ts +1 -1
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +31 -8
- package/src/store/chat/slices/aiChat/actions/rag.ts +1 -1
- package/src/store/chat/slices/message/selectors.test.ts +3 -3
- package/src/store/chat/slices/message/selectors.ts +50 -29
- package/src/store/chat/slices/plugin/action.ts +26 -8
- package/src/store/chat/slices/portal/action.ts +1 -0
- package/src/store/chat/slices/portal/initialState.ts +1 -0
- package/src/store/chat/slices/portal/selectors/thread.ts +17 -0
- package/src/store/chat/slices/portal/selectors.ts +2 -0
- package/src/store/chat/slices/thread/action.ts +326 -0
- package/src/store/chat/slices/thread/initialState.ts +34 -0
- package/src/store/chat/slices/thread/reducer.ts +48 -0
- package/src/store/chat/slices/thread/selectors/index.ts +202 -0
- package/src/store/chat/slices/thread/selectors/util.ts +22 -0
- package/src/store/chat/slices/topic/action.ts +5 -1
- package/src/store/chat/store.ts +5 -2
- package/src/store/global/initialState.ts +4 -0
- package/src/store/global/selectors.ts +4 -0
- package/src/store/user/slices/settings/selectors/systemAgent.ts +2 -0
- package/src/types/message/index.ts +17 -1
- package/src/types/topic/index.ts +1 -0
- package/src/types/topic/thread.ts +42 -0
- package/src/types/user/settings/systemAgent.ts +1 -0
- package/src/app/(main)/chat/(workspace)/@portal/features/Header.tsx +0 -11
- package/src/app/(main)/chat/(workspace)/_layout/Mobile/PortalModal.tsx +0 -35
- /package/src/{features → app/(main)/chat/(workspace)/@conversation/features}/ChatInput/Desktop/Footer/SendMore.tsx +0 -0
- /package/src/{features → app/(main)/chat/(workspace)/@conversation/features}/ChatInput/Desktop/Footer/ShortcutHint.tsx +0 -0
- /package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{DefaultContent.tsx → TopicItem/DefaultContent.tsx} +0 -0
- /package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{TopicContent.tsx → TopicItem/TopicContent.tsx} +0 -0
- /package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/PluginResultJSON.tsx +0 -0
- /package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/Settings.tsx +0 -0
- /package/src/features/Conversation/Messages/{Tool → Assistant/ToolCallItem}/Inspector/style.ts +0 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
import React, { memo, useMemo } from 'react';
|
2
|
+
|
3
|
+
import { ChatItem } from '@/features/Conversation';
|
4
|
+
import ActionsBar from '@/features/Conversation/components/ChatItem/ActionsBar';
|
5
|
+
import { useAgentStore } from '@/store/agent';
|
6
|
+
import { agentSelectors } from '@/store/agent/selectors';
|
7
|
+
import { useChatStore } from '@/store/chat';
|
8
|
+
import { threadSelectors } from '@/store/chat/selectors';
|
9
|
+
|
10
|
+
import ThreadDivider from './ThreadDivider';
|
11
|
+
|
12
|
+
export interface ThreadChatItemProps {
|
13
|
+
id: string;
|
14
|
+
index: number;
|
15
|
+
}
|
16
|
+
|
17
|
+
const ThreadChatItem = memo<ThreadChatItemProps>(({ id, index }) => {
|
18
|
+
const [threadMessageId, threadStartMessageIndex, historyLength] = useChatStore((s) => [
|
19
|
+
threadSelectors.threadSourceMessageId(s),
|
20
|
+
threadSelectors.threadSourceMessageIndex(s),
|
21
|
+
threadSelectors.portalDisplayChatsLength(s),
|
22
|
+
]);
|
23
|
+
|
24
|
+
const enableThreadDivider = threadMessageId === id;
|
25
|
+
|
26
|
+
const endRender = useMemo(
|
27
|
+
() => enableThreadDivider && <ThreadDivider />,
|
28
|
+
[enableThreadDivider, id],
|
29
|
+
);
|
30
|
+
|
31
|
+
const isParentMessage = index <= threadStartMessageIndex;
|
32
|
+
|
33
|
+
const actionBar = useMemo(
|
34
|
+
() => !isParentMessage && <ActionsBar id={id} inPortalThread />,
|
35
|
+
[id, isParentMessage],
|
36
|
+
);
|
37
|
+
|
38
|
+
const enableHistoryDivider = useAgentStore((s) => {
|
39
|
+
const config = agentSelectors.currentAgentChatConfig(s);
|
40
|
+
return (
|
41
|
+
config.enableHistoryCount &&
|
42
|
+
historyLength > (config.historyCount ?? 0) &&
|
43
|
+
config.historyCount === historyLength - index
|
44
|
+
);
|
45
|
+
});
|
46
|
+
|
47
|
+
return (
|
48
|
+
<ChatItem
|
49
|
+
actionBar={actionBar}
|
50
|
+
disableEditing={isParentMessage}
|
51
|
+
enableHistoryDivider={enableHistoryDivider}
|
52
|
+
endRender={endRender}
|
53
|
+
id={id}
|
54
|
+
inPortalThread
|
55
|
+
index={index}
|
56
|
+
/>
|
57
|
+
);
|
58
|
+
});
|
59
|
+
|
60
|
+
ThreadChatItem.displayName = 'ThreadChatItem';
|
61
|
+
|
62
|
+
export default ThreadChatItem;
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import React, { memo, useCallback } from 'react';
|
2
|
+
import { Flexbox } from 'react-layout-kit';
|
3
|
+
|
4
|
+
import { SkeletonList, VirtualizedList } from '@/features/Conversation';
|
5
|
+
import { useChatStore } from '@/store/chat';
|
6
|
+
import { threadSelectors } from '@/store/chat/selectors';
|
7
|
+
|
8
|
+
import ThreadChatItem from './ChatItem';
|
9
|
+
|
10
|
+
interface ChatListProps {
|
11
|
+
mobile?: boolean;
|
12
|
+
}
|
13
|
+
|
14
|
+
const ChatList = memo(({ mobile }: ChatListProps) => {
|
15
|
+
const data = useChatStore(threadSelectors.portalDisplayChatIDs);
|
16
|
+
const isInit = useChatStore((s) => s.threadsInit);
|
17
|
+
|
18
|
+
const useFetchThreads = useChatStore((s) => s.useFetchThreads);
|
19
|
+
|
20
|
+
useFetchThreads();
|
21
|
+
|
22
|
+
const itemContent = useCallback(
|
23
|
+
(index: number, id: string) => <ThreadChatItem id={id} index={index} />,
|
24
|
+
[mobile],
|
25
|
+
);
|
26
|
+
|
27
|
+
if (!isInit)
|
28
|
+
return (
|
29
|
+
<Flexbox flex={1} height={'100%'}>
|
30
|
+
<SkeletonList mobile={mobile} />
|
31
|
+
</Flexbox>
|
32
|
+
);
|
33
|
+
|
34
|
+
return (
|
35
|
+
<Flexbox
|
36
|
+
flex={1}
|
37
|
+
style={{
|
38
|
+
overflowX: 'hidden',
|
39
|
+
overflowY: 'auto',
|
40
|
+
position: 'relative',
|
41
|
+
}}
|
42
|
+
width={'100%'}
|
43
|
+
>
|
44
|
+
<VirtualizedList dataSource={data} itemContent={itemContent} mobile={mobile} />
|
45
|
+
</Flexbox>
|
46
|
+
);
|
47
|
+
});
|
48
|
+
|
49
|
+
export default ChatList;
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { Icon, Tag } from '@lobehub/ui';
|
2
|
+
import { Divider } from 'antd';
|
3
|
+
import { GitBranch } from 'lucide-react';
|
4
|
+
import { memo } from 'react';
|
5
|
+
import { useTranslation } from 'react-i18next';
|
6
|
+
|
7
|
+
const ThreadDivider = memo(() => {
|
8
|
+
const { t } = useTranslation('chat');
|
9
|
+
|
10
|
+
return (
|
11
|
+
<div style={{ padding: '0 20px' }}>
|
12
|
+
<Divider style={{ margin: 0, padding: '20px 0' }}>
|
13
|
+
<Tag icon={<Icon icon={GitBranch} />}>{t('thread.divider')}</Tag>
|
14
|
+
</Divider>
|
15
|
+
</div>
|
16
|
+
);
|
17
|
+
});
|
18
|
+
|
19
|
+
export default ThreadDivider;
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { Suspense, memo } from 'react';
|
2
|
+
import { Flexbox } from 'react-layout-kit';
|
3
|
+
|
4
|
+
import { SkeletonList } from '@/features/Conversation';
|
5
|
+
|
6
|
+
import ChatInput from './ChatInput';
|
7
|
+
import ChatList from './ChatList';
|
8
|
+
|
9
|
+
interface ConversationProps {
|
10
|
+
mobile?: boolean;
|
11
|
+
}
|
12
|
+
|
13
|
+
const Conversation = memo<ConversationProps>(({ mobile }) => (
|
14
|
+
<Flexbox height={'100%'}>
|
15
|
+
<Suspense
|
16
|
+
fallback={
|
17
|
+
<Flexbox flex={1} height={'100%'}>
|
18
|
+
<SkeletonList mobile={mobile} />
|
19
|
+
</Flexbox>
|
20
|
+
}
|
21
|
+
>
|
22
|
+
<ChatList mobile={mobile} />
|
23
|
+
</Suspense>
|
24
|
+
<ChatInput />
|
25
|
+
</Flexbox>
|
26
|
+
));
|
27
|
+
|
28
|
+
export default Conversation;
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import { Icon } from '@lobehub/ui';
|
2
|
+
import { Typography } from 'antd';
|
3
|
+
import isEqual from 'fast-deep-equal';
|
4
|
+
import { ListTree } from 'lucide-react';
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
6
|
+
|
7
|
+
import BubblesLoading from '@/components/BubblesLoading';
|
8
|
+
import { LOADING_FLAT } from '@/const/message';
|
9
|
+
import { useChatStore } from '@/store/chat';
|
10
|
+
import { portalThreadSelectors } from '@/store/chat/selectors';
|
11
|
+
import { oneLineEllipsis } from '@/styles';
|
12
|
+
|
13
|
+
const Active = () => {
|
14
|
+
const currentThread = useChatStore(portalThreadSelectors.portalCurrentThread, isEqual);
|
15
|
+
|
16
|
+
return (
|
17
|
+
currentThread && (
|
18
|
+
<Flexbox align={'center'} gap={8} horizontal style={{ marginInlineStart: 8 }}>
|
19
|
+
<Icon icon={ListTree} size={{ fontSize: 20 }} />
|
20
|
+
|
21
|
+
<Typography.Text className={oneLineEllipsis} style={{ fontSize: 16, fontWeight: 'bold' }}>
|
22
|
+
{currentThread?.title === LOADING_FLAT ? (
|
23
|
+
<Flexbox flex={1} height={30} justify={'center'}>
|
24
|
+
<BubblesLoading />
|
25
|
+
</Flexbox>
|
26
|
+
) : (
|
27
|
+
currentThread?.title
|
28
|
+
)}
|
29
|
+
</Typography.Text>
|
30
|
+
</Flexbox>
|
31
|
+
)
|
32
|
+
);
|
33
|
+
};
|
34
|
+
|
35
|
+
export default Active;
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import { Icon } from '@lobehub/ui';
|
2
|
+
import { Checkbox, Typography } from 'antd';
|
3
|
+
import { GitBranch } from 'lucide-react';
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
5
|
+
|
6
|
+
import { useChatStore } from '@/store/chat';
|
7
|
+
import { portalThreadSelectors } from '@/store/chat/selectors';
|
8
|
+
import { oneLineEllipsis } from '@/styles';
|
9
|
+
import { ThreadType } from '@/types/topic';
|
10
|
+
|
11
|
+
const NewThreadHeader = () => {
|
12
|
+
const [newThreadMode] = useChatStore((s) => [portalThreadSelectors.newThreadMode(s)]);
|
13
|
+
|
14
|
+
return (
|
15
|
+
<Flexbox>
|
16
|
+
<Flexbox align={'center'} gap={8} horizontal style={{ marginInlineStart: 8 }}>
|
17
|
+
<Icon icon={GitBranch} size={{ fontSize: 20 }} />
|
18
|
+
<Typography.Text className={oneLineEllipsis} style={{ fontSize: 16, fontWeight: 'bold' }}>
|
19
|
+
开启新的子话题
|
20
|
+
</Typography.Text>
|
21
|
+
<Checkbox
|
22
|
+
checked={newThreadMode === ThreadType.Continuation}
|
23
|
+
onChange={(e) => {
|
24
|
+
useChatStore.setState({
|
25
|
+
newThreadMode: e.target.checked ? ThreadType.Continuation : ThreadType.Standalone,
|
26
|
+
});
|
27
|
+
}}
|
28
|
+
style={{ marginInlineStart: 12 }}
|
29
|
+
>
|
30
|
+
包含话题上下文
|
31
|
+
</Checkbox>
|
32
|
+
</Flexbox>
|
33
|
+
</Flexbox>
|
34
|
+
);
|
35
|
+
};
|
36
|
+
|
37
|
+
export default NewThreadHeader;
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { Skeleton } from 'antd';
|
2
|
+
|
3
|
+
import { useChatStore } from '@/store/chat';
|
4
|
+
|
5
|
+
import ActiveThread from './Active';
|
6
|
+
import NewThread from './New';
|
7
|
+
|
8
|
+
const Header = () => {
|
9
|
+
const isInNew = useChatStore((s) => s.startToForkThread);
|
10
|
+
|
11
|
+
const isInit = useChatStore((s) => s.threadsInit);
|
12
|
+
|
13
|
+
if (!isInit) return <Skeleton.Button active size={'small'} style={{ height: 22, width: 200 }} />;
|
14
|
+
|
15
|
+
return isInNew ? <NewThread /> : <ActiveThread />;
|
16
|
+
};
|
17
|
+
|
18
|
+
export default Header;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { ActionIcon } from '@lobehub/ui';
|
2
|
+
import { XIcon } from 'lucide-react';
|
3
|
+
|
4
|
+
import SidebarHeader from '@/components/SidebarHeader';
|
5
|
+
import { useChatStore } from '@/store/chat';
|
6
|
+
|
7
|
+
import Title from './Title';
|
8
|
+
|
9
|
+
const Header = () => {
|
10
|
+
const closeThreadPortal = useChatStore((s) => s.closeThreadPortal);
|
11
|
+
return (
|
12
|
+
<SidebarHeader
|
13
|
+
actions={<ActionIcon icon={XIcon} onClick={closeThreadPortal} />}
|
14
|
+
style={{ paddingBlock: 8, paddingInline: 8 }}
|
15
|
+
title={<Title />}
|
16
|
+
/>
|
17
|
+
);
|
18
|
+
};
|
19
|
+
|
20
|
+
export default Header;
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import { useChatStore } from '@/store/chat';
|
2
|
+
import { portalThreadSelectors } from '@/store/chat/selectors';
|
3
|
+
|
4
|
+
export const useEnable = () => useChatStore(portalThreadSelectors.showThread);
|
5
|
+
|
6
|
+
export const onClose = () => {
|
7
|
+
useChatStore.setState({ portalThreadId: undefined });
|
8
|
+
};
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { PortalImpl } from '../type';
|
2
|
+
import Chat from './Chat';
|
3
|
+
import Header from './Header';
|
4
|
+
import { onClose, useEnable } from './hook';
|
5
|
+
|
6
|
+
export const Thread: PortalImpl = {
|
7
|
+
Body: Chat,
|
8
|
+
Header,
|
9
|
+
Title: () => null,
|
10
|
+
onClose,
|
11
|
+
useEnable,
|
12
|
+
};
|
@@ -7,10 +7,11 @@ import { FilePreview } from './FilePreview';
|
|
7
7
|
import { HomeBody, HomeTitle } from './Home';
|
8
8
|
import { MessageDetail } from './MessageDetail';
|
9
9
|
import { Plugins } from './Plugins';
|
10
|
+
import { Thread } from './Thread';
|
10
11
|
import Header from './components/Header';
|
11
12
|
import { PortalImpl } from './type';
|
12
13
|
|
13
|
-
const items: PortalImpl[] = [MessageDetail, Artifacts, Plugins, FilePreview];
|
14
|
+
const items: PortalImpl[] = [Thread, MessageDetail, Artifacts, Plugins, FilePreview];
|
14
15
|
|
15
16
|
export const PortalTitle = memo(() => {
|
16
17
|
const enabledList: boolean[] = [];
|
@@ -6,6 +6,12 @@ import { useSessionStore } from '@/store/session';
|
|
6
6
|
*/
|
7
7
|
export const useFetchTopics = () => {
|
8
8
|
const [sessionId] = useSessionStore((s) => [s.activeId]);
|
9
|
-
const [useFetchTopics] = useChatStore((s) => [
|
9
|
+
const [activeTopicId, useFetchTopics, useFetchThreads] = useChatStore((s) => [
|
10
|
+
s.activeTopicId,
|
11
|
+
s.useFetchTopics,
|
12
|
+
s.useFetchThreads,
|
13
|
+
]);
|
10
14
|
useFetchTopics(sessionId);
|
15
|
+
|
16
|
+
useFetchThreads(activeTopicId);
|
11
17
|
};
|
@@ -9,6 +9,7 @@ export default {
|
|
9
9
|
agents: '助手',
|
10
10
|
artifact: {
|
11
11
|
generating: '生成中',
|
12
|
+
inThread: '子话题中无法查看,请切换到主对话区打开',
|
12
13
|
thinking: '思考中',
|
13
14
|
thought: '思考过程',
|
14
15
|
unknownTitle: '未命名作品',
|
@@ -67,6 +68,7 @@ export default {
|
|
67
68
|
},
|
68
69
|
messageAction: {
|
69
70
|
delAndRegenerate: '删除并重新生成',
|
71
|
+
deleteDisabledByThreads: '存在子话题,不能删除',
|
70
72
|
regenerate: '重新生成',
|
71
73
|
},
|
72
74
|
newAgent: '新建助手',
|
@@ -123,6 +125,11 @@ export default {
|
|
123
125
|
loading: '识别中...',
|
124
126
|
prettifying: '润色中...',
|
125
127
|
},
|
128
|
+
thread: {
|
129
|
+
divider: '子话题',
|
130
|
+
threadMessageCount: '{{messageCount}} 条消息',
|
131
|
+
title: '子话题',
|
132
|
+
},
|
126
133
|
tokenDetails: {
|
127
134
|
chats: '会话消息',
|
128
135
|
historySummary: '历史总结',
|
@@ -152,8 +159,8 @@ export default {
|
|
152
159
|
action: '语音朗读',
|
153
160
|
clear: '删除语音',
|
154
161
|
},
|
155
|
-
updateAgent: '更新助理信息',
|
156
162
|
|
163
|
+
updateAgent: '更新助理信息',
|
157
164
|
upload: {
|
158
165
|
action: {
|
159
166
|
fileUpload: '上传文件',
|
@@ -16,6 +16,7 @@ import portal from './portal';
|
|
16
16
|
import providers from './providers';
|
17
17
|
import ragEval from './ragEval';
|
18
18
|
import setting from './setting';
|
19
|
+
import thread from './thread';
|
19
20
|
import tool from './tool';
|
20
21
|
import topic from './topic';
|
21
22
|
import welcome from './welcome';
|
@@ -39,6 +40,7 @@ const resources = {
|
|
39
40
|
providers,
|
40
41
|
ragEval,
|
41
42
|
setting,
|
43
|
+
thread,
|
42
44
|
tool,
|
43
45
|
topic,
|
44
46
|
welcome,
|
@@ -13,6 +13,7 @@ import { pluginRouter } from './plugin';
|
|
13
13
|
import { ragEvalRouter } from './ragEval';
|
14
14
|
import { sessionRouter } from './session';
|
15
15
|
import { sessionGroupRouter } from './sessionGroup';
|
16
|
+
import { threadRouter } from './thread';
|
16
17
|
import { topicRouter } from './topic';
|
17
18
|
import { userRouter } from './user';
|
18
19
|
|
@@ -28,6 +29,7 @@ export const lambdaRouter = router({
|
|
28
29
|
ragEval: ragEvalRouter,
|
29
30
|
session: sessionRouter,
|
30
31
|
sessionGroup: sessionGroupRouter,
|
32
|
+
thread: threadRouter,
|
31
33
|
topic: topicRouter,
|
32
34
|
user: userRouter,
|
33
35
|
});
|
@@ -0,0 +1,83 @@
|
|
1
|
+
import { z } from 'zod';
|
2
|
+
|
3
|
+
import { MessageModel } from '@/database/server/models/message';
|
4
|
+
import { ThreadModel } from '@/database/server/models/thread';
|
5
|
+
import { insertThreadSchema } from '@/database/server/schemas/lobechat';
|
6
|
+
import { authedProcedure, router } from '@/libs/trpc';
|
7
|
+
import { ThreadItem, createThreadSchema } from '@/types/topic/thread';
|
8
|
+
|
9
|
+
const threadProcedure = authedProcedure.use(async (opts) => {
|
10
|
+
const { ctx } = opts;
|
11
|
+
|
12
|
+
return opts.next({
|
13
|
+
ctx: {
|
14
|
+
messageModel: new MessageModel(ctx.userId),
|
15
|
+
threadModel: new ThreadModel(ctx.userId),
|
16
|
+
},
|
17
|
+
});
|
18
|
+
});
|
19
|
+
|
20
|
+
export const threadRouter = router({
|
21
|
+
createThread: threadProcedure.input(createThreadSchema).mutation(async ({ input, ctx }) => {
|
22
|
+
const thread = await ctx.threadModel.create({
|
23
|
+
parentThreadId: input.parentThreadId,
|
24
|
+
sourceMessageId: input.sourceMessageId,
|
25
|
+
title: input.title,
|
26
|
+
topicId: input.topicId,
|
27
|
+
type: input.type,
|
28
|
+
});
|
29
|
+
|
30
|
+
return thread?.id;
|
31
|
+
}),
|
32
|
+
createThreadWithMessage: threadProcedure
|
33
|
+
.input(
|
34
|
+
createThreadSchema.extend({
|
35
|
+
message: z.any(),
|
36
|
+
}),
|
37
|
+
)
|
38
|
+
.mutation(async ({ input, ctx }) => {
|
39
|
+
const thread = await ctx.threadModel.create({
|
40
|
+
parentThreadId: input.parentThreadId,
|
41
|
+
sourceMessageId: input.sourceMessageId,
|
42
|
+
title: input.message.content.slice(0, 20),
|
43
|
+
topicId: input.topicId,
|
44
|
+
type: input.type,
|
45
|
+
});
|
46
|
+
|
47
|
+
const message = await ctx.messageModel.create({ ...input.message, threadId: thread?.id });
|
48
|
+
|
49
|
+
return { messageId: message?.id, threadId: thread?.id };
|
50
|
+
}),
|
51
|
+
getThread: threadProcedure.query(async ({ ctx }): Promise<ThreadItem[]> => {
|
52
|
+
return ctx.threadModel.query() as any;
|
53
|
+
}),
|
54
|
+
|
55
|
+
getThreads: threadProcedure
|
56
|
+
.input(z.object({ topicId: z.string() }))
|
57
|
+
.query(async ({ input, ctx }) => {
|
58
|
+
return ctx.threadModel.queryByTopicId(input.topicId);
|
59
|
+
}),
|
60
|
+
|
61
|
+
removeAllThreads: threadProcedure.mutation(async ({ ctx }) => {
|
62
|
+
return ctx.threadModel.deleteAll();
|
63
|
+
}),
|
64
|
+
|
65
|
+
removeThread: threadProcedure
|
66
|
+
.input(z.object({ id: z.string(), removeChildren: z.boolean().optional() }))
|
67
|
+
.mutation(async ({ input, ctx }) => {
|
68
|
+
return ctx.threadModel.delete(input.id);
|
69
|
+
}),
|
70
|
+
|
71
|
+
updateThread: threadProcedure
|
72
|
+
.input(
|
73
|
+
z.object({
|
74
|
+
id: z.string(),
|
75
|
+
value: insertThreadSchema.partial(),
|
76
|
+
}),
|
77
|
+
)
|
78
|
+
.mutation(async ({ input, ctx }) => {
|
79
|
+
return ctx.threadModel.update(input.id, input.value);
|
80
|
+
}),
|
81
|
+
});
|
82
|
+
|
83
|
+
export type ThreadRouter = typeof threadRouter;
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import { INBOX_SESSION_ID } from '@/const/session';
|
2
|
+
import { lambdaClient } from '@/libs/trpc/client';
|
3
|
+
import { CreateMessageParams } from '@/types/message';
|
4
|
+
import { CreateThreadParams, ThreadItem } from '@/types/topic';
|
5
|
+
|
6
|
+
interface CreateThreadWithMessageParams extends CreateThreadParams {
|
7
|
+
message: CreateMessageParams;
|
8
|
+
}
|
9
|
+
export class ThreadService {
|
10
|
+
getThreads = (topicId: string): Promise<ThreadItem[]> => {
|
11
|
+
return lambdaClient.thread.getThreads.query({ topicId });
|
12
|
+
};
|
13
|
+
|
14
|
+
createThreadWithMessage({
|
15
|
+
message,
|
16
|
+
...params
|
17
|
+
}: CreateThreadWithMessageParams): Promise<{ messageId: string; threadId: string }> {
|
18
|
+
return lambdaClient.thread.createThreadWithMessage.mutate({
|
19
|
+
...params,
|
20
|
+
message: { ...message, sessionId: this.toDbSessionId(message.sessionId) },
|
21
|
+
});
|
22
|
+
}
|
23
|
+
|
24
|
+
// createThread(params: CreateThreadParams): Promise<string> {
|
25
|
+
// return lambdaClient.thread.createThread.mutate(params);
|
26
|
+
// }
|
27
|
+
|
28
|
+
updateThread(id: string, data: Partial<ThreadItem>): Promise<any> {
|
29
|
+
return lambdaClient.thread.updateThread.mutate({ id, value: data });
|
30
|
+
}
|
31
|
+
|
32
|
+
//
|
33
|
+
removeThread(id: string): Promise<any> {
|
34
|
+
return lambdaClient.thread.removeThread.mutate({ id });
|
35
|
+
}
|
36
|
+
//
|
37
|
+
// removeThreads(sessionId: string): Promise<any> {
|
38
|
+
// return lambdaClient.thread.batchDeleteBySessionId.mutate({ id: this.toDbSessionId(sessionId) });
|
39
|
+
// }
|
40
|
+
//
|
41
|
+
// batchRemoveThreads(topics: string[]): Promise<any> {
|
42
|
+
// return lambdaClient.thread.batchDelete.mutate({ ids: topics });
|
43
|
+
// }
|
44
|
+
//
|
45
|
+
// removeAllThread(): Promise<any> {
|
46
|
+
// return lambdaClient.thread.removeAllThreads.mutate();
|
47
|
+
// }
|
48
|
+
|
49
|
+
private toDbSessionId(sessionId: string | undefined) {
|
50
|
+
return sessionId === INBOX_SESSION_ID ? null : sessionId;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
export const threadService = new ThreadService();
|
@@ -5,12 +5,14 @@ import { ChatMessageState, initialMessageState } from './slices/message/initialS
|
|
5
5
|
import { ChatShareState, initialShareState } from './slices/share/initialState';
|
6
6
|
import { ChatTopicState, initialTopicState } from './slices/topic/initialState';
|
7
7
|
import { ChatAIChatState, initialAiChatState } from './slices/aiChat/initialState';
|
8
|
+
import { ChatThreadState, initialThreadState } from './slices/thread/initialState';
|
8
9
|
|
9
10
|
export type ChatStoreState = ChatTopicState &
|
10
11
|
ChatMessageState &
|
11
12
|
ChatAIChatState &
|
12
13
|
ChatToolState &
|
13
14
|
ChatShareState &
|
15
|
+
ChatThreadState &
|
14
16
|
ChatPortalState;
|
15
17
|
|
16
18
|
export const initialState: ChatStoreState = {
|
@@ -19,6 +21,7 @@ export const initialState: ChatStoreState = {
|
|
19
21
|
...initialTopicState,
|
20
22
|
...initialToolState,
|
21
23
|
...initialShareState,
|
24
|
+
...initialThreadState,
|
22
25
|
...initialChatPortalState,
|
23
26
|
|
24
27
|
// cloud
|
@@ -1,4 +1,5 @@
|
|
1
1
|
export { chatToolSelectors } from './slices/builtinTool/selectors';
|
2
2
|
export { chatSelectors } from './slices/message/selectors';
|
3
|
-
export
|
3
|
+
export * from './slices/portal/selectors';
|
4
|
+
export { threadSelectors } from './slices/thread/selectors';
|
4
5
|
export { topicSelectors } from './slices/topic/selectors';
|
@@ -527,7 +527,7 @@ describe('chatMessage actions', () => {
|
|
527
527
|
await result.current.regenerateMessage(messageId);
|
528
528
|
});
|
529
529
|
|
530
|
-
expect(resendMessageSpy).toHaveBeenCalledWith(messageId, 'abc');
|
530
|
+
expect(resendMessageSpy).toHaveBeenCalledWith(messageId, { traceId: 'abc' });
|
531
531
|
});
|
532
532
|
});
|
533
533
|
|
@@ -243,7 +243,7 @@ describe('chatRAG actions', () => {
|
|
243
243
|
}) as ChatMessage,
|
244
244
|
);
|
245
245
|
|
246
|
-
vi.spyOn(chatSelectors, '
|
246
|
+
vi.spyOn(chatSelectors, 'mainAIChatsWithHistoryConfig').mockReturnValue([
|
247
247
|
{ content: 'history' },
|
248
248
|
] as ChatMessage[]);
|
249
249
|
|