@lobehub/chat 1.28.5 → 1.29.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 +50 -0
- package/locales/ar/chat.json +1 -0
- package/locales/ar/setting.json +7 -2
- package/locales/bg-BG/chat.json +1 -0
- package/locales/bg-BG/setting.json +7 -2
- package/locales/de-DE/chat.json +1 -0
- package/locales/de-DE/setting.json +7 -2
- package/locales/en-US/chat.json +1 -0
- package/locales/en-US/setting.json +7 -2
- package/locales/es-ES/chat.json +1 -0
- package/locales/es-ES/setting.json +7 -2
- package/locales/fa-IR/chat.json +1 -0
- package/locales/fa-IR/setting.json +7 -2
- package/locales/fr-FR/chat.json +1 -0
- package/locales/fr-FR/setting.json +7 -2
- package/locales/it-IT/chat.json +1 -0
- package/locales/it-IT/setting.json +7 -2
- package/locales/ja-JP/chat.json +1 -0
- package/locales/ja-JP/setting.json +7 -2
- package/locales/ko-KR/chat.json +1 -0
- package/locales/ko-KR/setting.json +7 -2
- package/locales/nl-NL/chat.json +1 -0
- package/locales/nl-NL/setting.json +7 -2
- package/locales/pl-PL/chat.json +1 -0
- package/locales/pl-PL/setting.json +7 -2
- package/locales/pt-BR/chat.json +1 -0
- package/locales/pt-BR/setting.json +7 -2
- package/locales/ru-RU/chat.json +1 -0
- package/locales/ru-RU/setting.json +7 -2
- package/locales/tr-TR/chat.json +1 -0
- package/locales/tr-TR/setting.json +7 -2
- package/locales/vi-VN/chat.json +1 -0
- package/locales/vi-VN/setting.json +7 -2
- package/locales/zh-CN/chat.json +1 -0
- package/locales/zh-CN/setting.json +7 -2
- package/locales/zh-TW/chat.json +1 -0
- package/locales/zh-TW/setting.json +7 -2
- package/package.json +1 -1
- package/src/app/(main)/settings/system-agent/index.tsx +1 -0
- package/src/chains/__tests__/__snapshots__/summaryHistory.test.ts.snap +21 -0
- package/src/chains/__tests__/summaryHistory.test.ts +24 -0
- package/src/chains/summaryHistory.ts +19 -0
- package/src/const/settings/agent.ts +3 -1
- package/src/const/settings/systemAgent.ts +1 -0
- package/src/database/client/models/__tests__/session.test.ts +0 -1
- package/src/database/server/migrations/0011_add_topic_history_summary.sql +2 -0
- package/src/database/server/migrations/meta/0011_snapshot.json +3196 -0
- package/src/database/server/migrations/meta/_journal.json +7 -0
- package/src/database/server/models/__tests__/topic.test.ts +4 -0
- package/src/database/server/models/topic.ts +16 -0
- package/src/database/server/schemas/lobechat/topic.ts +3 -2
- package/src/features/AgentSetting/AgentChat/index.tsx +4 -18
- package/src/features/ChatInput/ActionBar/History.tsx +24 -21
- package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +22 -7
- package/src/features/Conversation/Actions/index.ts +2 -2
- package/src/features/Conversation/components/ChatItem/index.tsx +6 -6
- package/src/features/Conversation/components/History/index.tsx +71 -0
- package/src/features/Conversation/types/index.tsx +1 -1
- package/src/libs/next-auth/sso-providers/microsoft-entra-id-helper.ts +1 -1
- package/src/locales/default/chat.ts +1 -0
- package/src/locales/default/setting.ts +7 -2
- package/src/prompts/chatMessages/index.test.ts +94 -0
- package/src/prompts/chatMessages/index.ts +11 -0
- package/src/prompts/systemRole/index.ts +22 -0
- package/src/server/routers/lambda/topic.ts +7 -0
- package/src/services/__tests__/chat.test.ts +13 -61
- package/src/services/chat.ts +45 -11
- package/src/store/agent/slices/chat/__snapshots__/selectors.test.ts.snap +3 -1
- package/src/store/chat/helpers.ts +6 -2
- package/src/store/chat/slices/aiChat/actions/generateAIChat.ts +21 -8
- package/src/store/chat/slices/aiChat/actions/helpers.ts +9 -0
- package/src/store/chat/slices/aiChat/actions/index.ts +3 -1
- package/src/store/chat/slices/aiChat/actions/memory.ts +52 -0
- package/src/store/chat/slices/message/selectors.ts +1 -3
- package/src/store/chat/slices/topic/selectors.ts +24 -12
- package/src/store/chat/slices/{enchance → translate}/action.test.ts +0 -13
- package/src/store/chat/slices/{enchance → translate}/action.ts +5 -24
- package/src/store/chat/slices/tts/action.test.ts +63 -0
- package/src/store/chat/slices/tts/action.ts +35 -0
- package/src/store/chat/store.ts +6 -3
- package/src/store/file/reducers/uploadFileList.test.ts +197 -0
- package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +3 -1
- package/src/store/user/slices/settings/selectors/systemAgent.ts +2 -0
- package/src/types/agent/index.ts +2 -4
- package/src/types/topic.ts +13 -0
- package/src/types/user/settings/systemAgent.ts +1 -0
- package/src/utils/tokenizer/client.ts +1 -1
- /package/src/features/Conversation/components/{ChatItem → History}/HistoryDivider.tsx +0 -0
@@ -77,6 +77,13 @@
|
|
77
77
|
"when": 1730900133049,
|
78
78
|
"tag": "0010_add_accessed_at_and_clean_tables",
|
79
79
|
"breakpoints": true
|
80
|
+
},
|
81
|
+
{
|
82
|
+
"idx": 11,
|
83
|
+
"version": "7",
|
84
|
+
"when": 1731138670427,
|
85
|
+
"tag": "0011_add_topic_history_summary",
|
86
|
+
"breakpoints": true
|
80
87
|
}
|
81
88
|
],
|
82
89
|
"version": "6"
|
@@ -427,6 +427,8 @@ describe('TopicModel', () => {
|
|
427
427
|
favorite: true,
|
428
428
|
sessionId,
|
429
429
|
userId,
|
430
|
+
historySummary: null,
|
431
|
+
metadata: null,
|
430
432
|
clientId: null,
|
431
433
|
createdAt: expect.any(Date),
|
432
434
|
updatedAt: expect.any(Date),
|
@@ -473,6 +475,8 @@ describe('TopicModel', () => {
|
|
473
475
|
title: 'New Topic',
|
474
476
|
favorite: false,
|
475
477
|
clientId: null,
|
478
|
+
historySummary: null,
|
479
|
+
metadata: null,
|
476
480
|
sessionId,
|
477
481
|
userId,
|
478
482
|
createdAt: expect.any(Date),
|
@@ -36,6 +36,8 @@ export class TopicModel {
|
|
36
36
|
createdAt: topics.createdAt,
|
37
37
|
favorite: topics.favorite,
|
38
38
|
id: topics.id,
|
39
|
+
metadata: topics.metadata,
|
40
|
+
summary: topics.historySummary,
|
39
41
|
title: topics.title,
|
40
42
|
updatedAt: topics.updatedAt,
|
41
43
|
})
|
@@ -47,6 +49,20 @@ export class TopicModel {
|
|
47
49
|
.limit(pageSize)
|
48
50
|
.offset(offset)
|
49
51
|
);
|
52
|
+
|
53
|
+
// return result.map(({ summary, metadata, ...item }) => {
|
54
|
+
// const meta = metadata as ChatTopicMetadata;
|
55
|
+
// return {
|
56
|
+
// ...item,
|
57
|
+
// summary: !!summary
|
58
|
+
// ? ({
|
59
|
+
// content: summary,
|
60
|
+
// model: meta?.model,
|
61
|
+
// provider: meta?.provider,
|
62
|
+
// } as ChatTopicSummary)
|
63
|
+
// : undefined,
|
64
|
+
// };
|
65
|
+
// });
|
50
66
|
}
|
51
67
|
|
52
68
|
async findById(id: string) {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
2
|
-
import { boolean, pgTable, text, unique } from 'drizzle-orm/pg-core';
|
2
|
+
import { boolean, jsonb, pgTable, text, unique } from 'drizzle-orm/pg-core';
|
3
3
|
|
4
4
|
import { idGenerator } from '../../utils/idGenerator';
|
5
5
|
import { timestamps } from './_helpers';
|
@@ -19,7 +19,8 @@ export const topics = pgTable(
|
|
19
19
|
.references(() => users.id, { onDelete: 'cascade' })
|
20
20
|
.notNull(),
|
21
21
|
clientId: text('client_id'),
|
22
|
-
|
22
|
+
historySummary: text('history_summary'),
|
23
|
+
metadata: jsonb('metadata'),
|
23
24
|
...timestamps,
|
24
25
|
},
|
25
26
|
(t) => ({
|
@@ -18,20 +18,13 @@ const AgentChat = memo(() => {
|
|
18
18
|
const { t } = useTranslation('setting');
|
19
19
|
const [form] = Form.useForm();
|
20
20
|
const { isDarkMode } = useThemeMode();
|
21
|
-
const [
|
22
|
-
displayMode,
|
23
|
-
enableAutoCreateTopic,
|
24
|
-
enableHistoryCount,
|
25
|
-
enableCompressThreshold,
|
26
|
-
updateConfig,
|
27
|
-
] = useStore((s) => {
|
21
|
+
const [displayMode, enableAutoCreateTopic, enableHistoryCount, updateConfig] = useStore((s) => {
|
28
22
|
const config = selectors.chatConfig(s);
|
29
23
|
|
30
24
|
return [
|
31
25
|
config.displayMode,
|
32
26
|
config.enableAutoCreateTopic,
|
33
27
|
config.enableHistoryCount,
|
34
|
-
config.enableCompressThreshold,
|
35
28
|
s.setChatConfig,
|
36
29
|
];
|
37
30
|
});
|
@@ -110,19 +103,12 @@ const AgentChat = memo(() => {
|
|
110
103
|
},
|
111
104
|
{
|
112
105
|
children: <Switch />,
|
113
|
-
|
106
|
+
hidden: !enableHistoryCount,
|
107
|
+
label: t('settingChat.enableCompressHistory.title'),
|
114
108
|
minWidth: undefined,
|
115
|
-
name: '
|
109
|
+
name: 'enableCompressHistory',
|
116
110
|
valuePropName: 'checked',
|
117
111
|
},
|
118
|
-
{
|
119
|
-
children: <SliderWithInput max={32} min={0} />,
|
120
|
-
desc: t('settingChat.compressThreshold.desc'),
|
121
|
-
divider: false,
|
122
|
-
hidden: !enableCompressThreshold,
|
123
|
-
label: t('settingChat.compressThreshold.title'),
|
124
|
-
name: 'compressThreshold',
|
125
|
-
},
|
126
112
|
],
|
127
113
|
title: t('settingChat.title'),
|
128
114
|
};
|
@@ -5,6 +5,7 @@ import { memo, useState } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
7
7
|
|
8
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
8
9
|
import { useAgentStore } from '@/store/agent';
|
9
10
|
import { agentSelectors } from '@/store/agent/selectors';
|
10
11
|
|
@@ -12,17 +13,18 @@ const History = memo(() => {
|
|
12
13
|
const { t } = useTranslation('setting');
|
13
14
|
const [popoverOpen, setPopoverOpen] = useState(false);
|
14
15
|
|
15
|
-
const [historyCount,
|
16
|
+
const [historyCount, enableHistoryCount, updateAgentConfig] = useAgentStore((s) => {
|
16
17
|
const config = agentSelectors.currentAgentChatConfig(s);
|
17
|
-
return [config.historyCount,
|
18
|
+
return [config.historyCount, config.enableHistoryCount, s.updateAgentChatConfig];
|
18
19
|
});
|
19
20
|
|
20
21
|
const title = t(
|
21
|
-
|
22
|
-
? 'settingChat.enableHistoryCount.
|
23
|
-
: 'settingChat.enableHistoryCount.
|
22
|
+
enableHistoryCount
|
23
|
+
? 'settingChat.enableHistoryCount.limited'
|
24
|
+
: 'settingChat.enableHistoryCount.unlimited',
|
24
25
|
{ number: historyCount || 0 },
|
25
26
|
);
|
27
|
+
const mobile = useIsMobile();
|
26
28
|
|
27
29
|
return (
|
28
30
|
<Popover
|
@@ -30,36 +32,37 @@ const History = memo(() => {
|
|
30
32
|
content={
|
31
33
|
<Flexbox align={'center'} gap={16} horizontal>
|
32
34
|
<SliderWithInput
|
33
|
-
disabled={
|
34
|
-
max={
|
35
|
-
min={
|
35
|
+
disabled={!enableHistoryCount}
|
36
|
+
max={20}
|
37
|
+
min={0}
|
36
38
|
onChange={(v) => {
|
37
39
|
updateAgentConfig({ historyCount: v });
|
38
40
|
}}
|
39
41
|
step={1}
|
40
|
-
style={{ width: 160 }}
|
42
|
+
style={{ width: mobile ? 160 : 300 }}
|
41
43
|
value={historyCount}
|
42
44
|
/>
|
43
|
-
<Flexbox align={'center'} gap={4} horizontal>
|
44
|
-
<Switch
|
45
|
-
checked={unlimited}
|
46
|
-
onChange={(checked) => {
|
47
|
-
updateAgentConfig({ enableHistoryCount: !checked });
|
48
|
-
}}
|
49
|
-
size={'small'}
|
50
|
-
/>
|
51
|
-
{t('settingChat.enableHistoryCount.alias')}
|
52
|
-
</Flexbox>
|
53
45
|
</Flexbox>
|
54
46
|
}
|
55
47
|
onOpenChange={setPopoverOpen}
|
56
48
|
open={popoverOpen}
|
57
49
|
placement={'top'}
|
58
|
-
title={
|
50
|
+
title={
|
51
|
+
<Flexbox align={'center'} gap={4} horizontal>
|
52
|
+
<Switch
|
53
|
+
checked={enableHistoryCount}
|
54
|
+
onChange={(enableHistoryCount) => {
|
55
|
+
updateAgentConfig({ enableHistoryCount });
|
56
|
+
}}
|
57
|
+
size={'small'}
|
58
|
+
/>
|
59
|
+
{t('settingChat.enableHistoryCount.title')}
|
60
|
+
</Flexbox>
|
61
|
+
}
|
59
62
|
trigger={'click'}
|
60
63
|
>
|
61
64
|
<ActionIcon
|
62
|
-
icon={
|
65
|
+
icon={enableHistoryCount ? Timer : TimerOff}
|
63
66
|
placement={'bottom'}
|
64
67
|
title={popoverOpen ? undefined : title}
|
65
68
|
/>
|
@@ -10,7 +10,7 @@ import { useTokenCount } from '@/hooks/useTokenCount';
|
|
10
10
|
import { useAgentStore } from '@/store/agent';
|
11
11
|
import { agentSelectors } from '@/store/agent/selectors';
|
12
12
|
import { useChatStore } from '@/store/chat';
|
13
|
-
import { chatSelectors } from '@/store/chat/selectors';
|
13
|
+
import { chatSelectors, topicSelectors } from '@/store/chat/selectors';
|
14
14
|
import { useToolStore } from '@/store/tool';
|
15
15
|
import { toolSelectors } from '@/store/tool/selectors';
|
16
16
|
import { useUserStore } from '@/store/user';
|
@@ -22,15 +22,23 @@ const Token = memo(() => {
|
|
22
22
|
const { t } = useTranslation(['chat', 'components']);
|
23
23
|
const theme = useTheme();
|
24
24
|
|
25
|
-
const [input, messageString] = useChatStore((s) => [
|
25
|
+
const [input, messageString, historySummary] = useChatStore((s) => [
|
26
26
|
s.inputMessage,
|
27
27
|
chatSelectors.chatsMessageString(s),
|
28
|
+
topicSelectors.currentActiveTopicSummary(s)?.content || '',
|
28
29
|
]);
|
29
30
|
|
30
|
-
const [systemRole, model] = useAgentStore((s) =>
|
31
|
-
agentSelectors.
|
32
|
-
|
33
|
-
|
31
|
+
const [systemRole, model] = useAgentStore((s) => {
|
32
|
+
const config = agentSelectors.currentAgentChatConfig(s);
|
33
|
+
|
34
|
+
return [
|
35
|
+
agentSelectors.currentAgentSystemRole(s),
|
36
|
+
agentSelectors.currentAgentModel(s) as string,
|
37
|
+
// add these two params to enable the component to re-render
|
38
|
+
config.historyCount,
|
39
|
+
config.enableHistoryCount,
|
40
|
+
];
|
41
|
+
});
|
34
42
|
|
35
43
|
const maxTokens = useUserStore(modelProviderSelectors.modelMaxToken(model));
|
36
44
|
|
@@ -55,9 +63,10 @@ const Token = memo(() => {
|
|
55
63
|
|
56
64
|
// SystemRole token
|
57
65
|
const systemRoleToken = useTokenCount(systemRole);
|
66
|
+
const historySummaryToken = useTokenCount(historySummary);
|
58
67
|
|
59
68
|
// Total token
|
60
|
-
const totalToken = systemRoleToken + toolsToken + chatsToken;
|
69
|
+
const totalToken = systemRoleToken + historySummaryToken + toolsToken + chatsToken;
|
61
70
|
|
62
71
|
const content = (
|
63
72
|
<Flexbox gap={12} style={{ minWidth: 200 }}>
|
@@ -99,6 +108,12 @@ const Token = memo(() => {
|
|
99
108
|
title: t('tokenDetails.tools'),
|
100
109
|
value: toolsToken,
|
101
110
|
},
|
111
|
+
{
|
112
|
+
color: theme.orange,
|
113
|
+
id: 'historySummary',
|
114
|
+
title: t('tokenDetails.historySummary'),
|
115
|
+
value: historySummaryToken,
|
116
|
+
},
|
102
117
|
{
|
103
118
|
color: theme.gold,
|
104
119
|
id: 'chats',
|
@@ -3,7 +3,7 @@ import { useCallback } from 'react';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
4
4
|
|
5
5
|
import { useChatStore } from '@/store/chat';
|
6
|
-
import {
|
6
|
+
import { MessageRoleType } from '@/types/message';
|
7
7
|
|
8
8
|
import { OnActionsClick, RenderAction } from '../types';
|
9
9
|
import { AssistantActionsBar } from './Assistant';
|
@@ -11,7 +11,7 @@ import { DefaultActionsBar } from './Fallback';
|
|
11
11
|
import { ToolActionsBar } from './Tool';
|
12
12
|
import { UserActionsBar } from './User';
|
13
13
|
|
14
|
-
export const renderActions: Record<
|
14
|
+
export const renderActions: Record<MessageRoleType, RenderAction> = {
|
15
15
|
assistant: AssistantActionsBar,
|
16
16
|
system: DefaultActionsBar,
|
17
17
|
tool: ToolActionsBar,
|
@@ -22,9 +22,9 @@ import {
|
|
22
22
|
renderMessages,
|
23
23
|
useAvatarsClick,
|
24
24
|
} from '../../Messages';
|
25
|
+
import History from '../History';
|
25
26
|
import { markdownElements } from '../MarkdownElements';
|
26
27
|
import ActionsBar from './ActionsBar';
|
27
|
-
import HistoryDivider from './HistoryDivider';
|
28
28
|
import { processWithArtifact } from './utils';
|
29
29
|
|
30
30
|
const rehypePlugins = markdownElements.map((element) => element.rehypePlugin);
|
@@ -61,11 +61,9 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
61
61
|
|
62
62
|
if (index >= chats.length) return;
|
63
63
|
|
64
|
-
return
|
64
|
+
return chats[index];
|
65
65
|
}, isEqual);
|
66
66
|
|
67
|
-
const historyLength = useChatStore((s) => chatSelectors.currentChats(s).length);
|
68
|
-
|
69
67
|
const [
|
70
68
|
isMessageLoading,
|
71
69
|
generating,
|
@@ -138,12 +136,14 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
138
136
|
|
139
137
|
const error = useErrorContent(item?.error);
|
140
138
|
|
139
|
+
const historyLength = useChatStore((s) => chatSelectors.currentChats(s).length);
|
140
|
+
|
141
141
|
const enableHistoryDivider = useAgentStore((s) => {
|
142
142
|
const config = agentSelectors.currentAgentChatConfig(s);
|
143
143
|
return (
|
144
144
|
config.enableHistoryCount &&
|
145
145
|
historyLength > (config.historyCount ?? 0) &&
|
146
|
-
config.historyCount === historyLength - index
|
146
|
+
config.historyCount === historyLength - index
|
147
147
|
);
|
148
148
|
});
|
149
149
|
|
@@ -166,7 +166,7 @@ const Item = memo<ChatListItemProps>(({ index, id }) => {
|
|
166
166
|
return (
|
167
167
|
item && (
|
168
168
|
<>
|
169
|
-
|
169
|
+
{enableHistoryDivider && <History />}
|
170
170
|
<ChatItem
|
171
171
|
actions={
|
172
172
|
<ActionsBar
|
@@ -0,0 +1,71 @@
|
|
1
|
+
import { ModelTag } from '@lobehub/icons';
|
2
|
+
import { Icon, Markdown } from '@lobehub/ui';
|
3
|
+
import { Typography } from 'antd';
|
4
|
+
import { createStyles } from 'antd-style';
|
5
|
+
import { ScrollText } from 'lucide-react';
|
6
|
+
import { memo } from 'react';
|
7
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
8
|
+
|
9
|
+
import { useChatStore } from '@/store/chat';
|
10
|
+
import { topicSelectors } from '@/store/chat/selectors';
|
11
|
+
|
12
|
+
import HistoryDivider from './HistoryDivider';
|
13
|
+
|
14
|
+
const useStyles = createStyles(({ css, token }) => ({
|
15
|
+
container: css`
|
16
|
+
padding-inline: 12px;
|
17
|
+
border-radius: 12px;
|
18
|
+
`,
|
19
|
+
content: css`
|
20
|
+
color: ${token.colorTextDescription};
|
21
|
+
`,
|
22
|
+
line: css`
|
23
|
+
width: 3px;
|
24
|
+
height: 100%;
|
25
|
+
background: ${token.colorBorder};
|
26
|
+
`,
|
27
|
+
}));
|
28
|
+
|
29
|
+
const History = memo(() => {
|
30
|
+
const { styles, theme } = useStyles();
|
31
|
+
const [content, model] = useChatStore((s) => {
|
32
|
+
const history = topicSelectors.currentActiveTopicSummary(s);
|
33
|
+
return [history?.content, history?.model];
|
34
|
+
});
|
35
|
+
|
36
|
+
return (
|
37
|
+
<Flexbox paddingInline={16} style={{ paddingBottom: 8 }}>
|
38
|
+
<HistoryDivider enable />
|
39
|
+
{!!content && (
|
40
|
+
<Flexbox className={styles.container} gap={8}>
|
41
|
+
<Flexbox align={'flex-start'} gap={8} horizontal>
|
42
|
+
<Center height={20} width={20}>
|
43
|
+
<Icon
|
44
|
+
icon={ScrollText}
|
45
|
+
size={{ fontSize: 16 }}
|
46
|
+
style={{ color: theme.colorTextDescription }}
|
47
|
+
/>
|
48
|
+
</Center>
|
49
|
+
<Typography.Text type={'secondary'}>历史消息总结</Typography.Text>
|
50
|
+
|
51
|
+
{model && (
|
52
|
+
<div>
|
53
|
+
<ModelTag model={model} />
|
54
|
+
</div>
|
55
|
+
)}
|
56
|
+
</Flexbox>
|
57
|
+
<Flexbox align={'flex-start'} gap={8} horizontal>
|
58
|
+
<Flexbox align={'center'} padding={8} width={20}>
|
59
|
+
<div className={styles.line}></div>
|
60
|
+
</Flexbox>
|
61
|
+
<Markdown className={styles.content} variant={'chat'}>
|
62
|
+
{content}
|
63
|
+
</Markdown>
|
64
|
+
</Flexbox>
|
65
|
+
</Flexbox>
|
66
|
+
)}
|
67
|
+
</Flexbox>
|
68
|
+
);
|
69
|
+
});
|
70
|
+
|
71
|
+
export default History;
|
@@ -9,7 +9,7 @@ import { type ActionsBarProps } from '../components/ChatItem/ActionsBar';
|
|
9
9
|
|
10
10
|
export type OnActionsClick = (action: ActionEvent, message: ChatMessage) => void;
|
11
11
|
export type OnAvatarsClick = (role: RenderRole) => ChatItemProps['onAvatarClick'];
|
12
|
-
export type RenderRole = LLMRoleType | 'default' | string;
|
12
|
+
export type RenderRole = LLMRoleType | 'default' | 'history' | string;
|
13
13
|
export type RenderMessage = FC<ChatMessage & { editableContent: ReactNode }>;
|
14
14
|
export type RenderBelowMessage = FC<ChatMessage>;
|
15
15
|
export type RenderMessageExtra = FC<ChatMessage>;
|
@@ -177,8 +177,8 @@ export default {
|
|
177
177
|
desc: '会话过程中是否自动创建话题,仅在临时话题中生效',
|
178
178
|
title: '自动创建话题',
|
179
179
|
},
|
180
|
-
|
181
|
-
title: '
|
180
|
+
enableCompressHistory: {
|
181
|
+
title: '开启历史消息自动总结',
|
182
182
|
},
|
183
183
|
enableHistoryCount: {
|
184
184
|
alias: '不限制',
|
@@ -380,6 +380,11 @@ export default {
|
|
380
380
|
placeholder: '请输入自定义提示词',
|
381
381
|
title: '自定义提示词',
|
382
382
|
},
|
383
|
+
historyCompress: {
|
384
|
+
label: '会话历史模型',
|
385
|
+
modelDesc: '指定用于压缩会话历史的模型',
|
386
|
+
title: '自动总结会话历史',
|
387
|
+
},
|
383
388
|
queryRewrite: {
|
384
389
|
label: '提问重写模型',
|
385
390
|
modelDesc: '指定用于优化用户提问的模型',
|
@@ -0,0 +1,94 @@
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
2
|
+
|
3
|
+
import { ChatMessage } from '@/types/message';
|
4
|
+
|
5
|
+
import { chatHistoryPrompts } from './index';
|
6
|
+
|
7
|
+
describe('chatHistoryPrompts', () => {
|
8
|
+
// Test with empty messages array
|
9
|
+
it('should return empty chat history with empty messages', () => {
|
10
|
+
const messages: ChatMessage[] = [];
|
11
|
+
const result = chatHistoryPrompts(messages);
|
12
|
+
|
13
|
+
expect(result).toBe(`<chat_history>
|
14
|
+
|
15
|
+
</chat_history>`);
|
16
|
+
});
|
17
|
+
|
18
|
+
// Test with single message
|
19
|
+
it('should format single message correctly', () => {
|
20
|
+
const messages = [
|
21
|
+
{
|
22
|
+
role: 'user',
|
23
|
+
content: 'Hello',
|
24
|
+
},
|
25
|
+
] as ChatMessage[];
|
26
|
+
const result = chatHistoryPrompts(messages);
|
27
|
+
|
28
|
+
expect(result).toBe(`<chat_history>
|
29
|
+
<user>Hello</user>
|
30
|
+
</chat_history>`);
|
31
|
+
});
|
32
|
+
|
33
|
+
// Test with multiple messages
|
34
|
+
it('should format multiple messages correctly', () => {
|
35
|
+
const messages = [
|
36
|
+
{
|
37
|
+
role: 'user',
|
38
|
+
content: 'Hello',
|
39
|
+
},
|
40
|
+
{
|
41
|
+
role: 'assistant',
|
42
|
+
content: 'Hi there!',
|
43
|
+
},
|
44
|
+
{
|
45
|
+
role: 'user',
|
46
|
+
content: 'How are you?',
|
47
|
+
},
|
48
|
+
] as ChatMessage[];
|
49
|
+
const result = chatHistoryPrompts(messages);
|
50
|
+
|
51
|
+
expect(result).toBe(`<chat_history>
|
52
|
+
<user>Hello</user>
|
53
|
+
<assistant>Hi there!</assistant>
|
54
|
+
<user>How are you?</user>
|
55
|
+
</chat_history>`);
|
56
|
+
});
|
57
|
+
|
58
|
+
// Test with messages containing special characters
|
59
|
+
it('should handle messages with special characters', () => {
|
60
|
+
const messages = [
|
61
|
+
{
|
62
|
+
role: 'user',
|
63
|
+
content: 'Hello & goodbye',
|
64
|
+
},
|
65
|
+
{
|
66
|
+
role: 'assistant',
|
67
|
+
content: '<test> & </test>',
|
68
|
+
},
|
69
|
+
] as ChatMessage[];
|
70
|
+
|
71
|
+
const result = chatHistoryPrompts(messages);
|
72
|
+
|
73
|
+
expect(result).toBe(`<chat_history>
|
74
|
+
<user>Hello & goodbye</user>
|
75
|
+
<assistant><test> & </test></assistant>
|
76
|
+
</chat_history>`);
|
77
|
+
});
|
78
|
+
|
79
|
+
// Test with messages containing multiple lines
|
80
|
+
it('should handle multi-line messages correctly', () => {
|
81
|
+
const messages = [
|
82
|
+
{
|
83
|
+
role: 'user',
|
84
|
+
content: 'Line 1\nLine 2',
|
85
|
+
},
|
86
|
+
] as ChatMessage[];
|
87
|
+
|
88
|
+
const result = chatHistoryPrompts(messages);
|
89
|
+
|
90
|
+
expect(result).toBe(`<chat_history>
|
91
|
+
<user>Line 1\nLine 2</user>
|
92
|
+
</chat_history>`);
|
93
|
+
});
|
94
|
+
});
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { ChatMessage } from '@/types/message';
|
2
|
+
|
3
|
+
const chatMessage = (message: ChatMessage) => {
|
4
|
+
return `<${message.role}>${message.content}</${message.role}>`;
|
5
|
+
};
|
6
|
+
|
7
|
+
export const chatHistoryPrompts = (messages: ChatMessage[]) => {
|
8
|
+
return `<chat_history>
|
9
|
+
${messages.map((m) => chatMessage(m)).join('\n')}
|
10
|
+
</chat_history>`;
|
11
|
+
};
|
@@ -0,0 +1,22 @@
|
|
1
|
+
const historySummaryPrompt = (historySummary: string) => `<chat_history_summary>
|
2
|
+
<docstring>Users may have lots of chat messages,here is the summary of the hisotry:</docstring>
|
3
|
+
<summary>${historySummary}</summary>
|
4
|
+
</chat_history_summary>
|
5
|
+
`;
|
6
|
+
|
7
|
+
/**
|
8
|
+
* Lobe Chat will inject some system instructions here
|
9
|
+
*/
|
10
|
+
export const BuiltinSystemRolePrompts = ({
|
11
|
+
welcome,
|
12
|
+
plugins,
|
13
|
+
historySummary,
|
14
|
+
}: {
|
15
|
+
historySummary?: string;
|
16
|
+
plugins?: string;
|
17
|
+
welcome?: string;
|
18
|
+
}) => {
|
19
|
+
return [welcome, plugins, historySummary ? historySummaryPrompt(historySummary) : '']
|
20
|
+
.filter(Boolean)
|
21
|
+
.join('\n\n');
|
22
|
+
};
|
@@ -121,7 +121,14 @@ export const topicRouter = router({
|
|
121
121
|
value: z.object({
|
122
122
|
favorite: z.boolean().optional(),
|
123
123
|
messages: z.array(z.string()).optional(),
|
124
|
+
metadata: z
|
125
|
+
.object({
|
126
|
+
model: z.string().optional(),
|
127
|
+
provider: z.string().optional(),
|
128
|
+
})
|
129
|
+
.optional(),
|
124
130
|
sessionId: z.string().optional(),
|
131
|
+
summary: z.string().optional(),
|
125
132
|
title: z.string().optional(),
|
126
133
|
}),
|
127
134
|
}),
|