@lobehub/chat 0.29.0 → 0.30.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/.eslintrc.js +3 -0
- package/CHANGELOG.md +28 -0
- package/package.json +1 -1
- package/src/const/message.ts +2 -0
- package/src/locales/default/common.ts +2 -0
- package/src/pages/chat/[id]/Config/SideBar.tsx +1 -1
- package/src/pages/chat/[id]/Config/Topic/DefaultContent.tsx +29 -0
- package/src/pages/chat/[id]/Config/Topic/TopicContent.tsx +151 -0
- package/src/pages/chat/[id]/Config/Topic/TopicItem.tsx +70 -0
- package/src/pages/chat/[id]/Config/{Topic.tsx → Topic/index.tsx} +1 -8
- package/src/pages/chat/[id]/Config/index.tsx +3 -5
- package/src/pages/chat/[id]/Conversation/Input/index.tsx +7 -10
- package/src/pages/chat/[id]/Header.tsx +3 -2
- package/src/store/session/slices/agentConfig/action.ts +0 -11
- package/src/store/session/slices/agentConfig/initialState.ts +0 -4
- package/src/store/session/slices/chat/actions/message.ts +2 -2
- package/src/store/session/slices/chat/actions/topic.ts +28 -2
- package/src/store/session/slices/chat/initialState.ts +1 -0
- package/src/store/session/slices/chat/reducers/topic.ts +23 -1
- package/src/store/session/slices/chat/selectors/index.ts +2 -1
- package/src/store/session/slices/chat/selectors/topic.ts +8 -0
- package/src/store/settings/action.ts +7 -1
- package/src/store/settings/initialState.ts +2 -0
- package/src/pages/chat/[id]/Config/TopicItem.tsx +0 -136
package/.eslintrc.js
CHANGED
|
@@ -4,5 +4,8 @@ config.extends.push('plugin:@next/next/recommended');
|
|
|
4
4
|
|
|
5
5
|
config.rules['unicorn/no-negated-condition'] = 0;
|
|
6
6
|
config.rules['unicorn/prefer-type-error'] = 0;
|
|
7
|
+
config.rules['unicorn/prefer-logical-operator-over-ternary'] = 0;
|
|
8
|
+
config.rules['unicorn/no-null'] = 0;
|
|
9
|
+
config.rules['unicorn/no-typeof-undefined'] = 0;
|
|
7
10
|
|
|
8
11
|
module.exports = config;
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 0.30.0](https://github.com/lobehub/lobe-chat/compare/v0.29.0...v0.30.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-07-30**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: 优化保存为话题功能, 实现 Topic 重命名功能, 实现话题删除功能, 支持缓存角色面板的展开折叠状态.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: 优化保存为话题功能 ([fdbe084](https://github.com/lobehub/lobe-chat/commit/fdbe084))
|
|
21
|
+
- **misc**: 实现 Topic 重命名功能 ([5ef1685](https://github.com/lobehub/lobe-chat/commit/5ef1685))
|
|
22
|
+
- **misc**: 实现话题删除功能 ([970889d](https://github.com/lobehub/lobe-chat/commit/970889d))
|
|
23
|
+
- **misc**: 支持缓存角色面板的展开折叠状态 ([c241c4b](https://github.com/lobehub/lobe-chat/commit/c241c4b))
|
|
24
|
+
|
|
25
|
+
</details>
|
|
26
|
+
|
|
27
|
+
<div align="right">
|
|
28
|
+
|
|
29
|
+
[](#readme-top)
|
|
30
|
+
|
|
31
|
+
</div>
|
|
32
|
+
|
|
5
33
|
## [Version 0.29.0](https://github.com/lobehub/lobe-chat/compare/v0.28.0...v0.29.0)
|
|
6
34
|
|
|
7
35
|
<sup>Released on **2023-07-30**</sup>
|
package/package.json
CHANGED
package/src/const/message.ts
CHANGED
|
@@ -52,6 +52,8 @@ export default {
|
|
|
52
52
|
temp: '临时',
|
|
53
53
|
tokenDetail: '系统设定: {{systemRoleToken}} 历史消息: {{chatsToken}}',
|
|
54
54
|
topic: {
|
|
55
|
+
confirmRemoveTopic: '即将删除该话题,删除后将不可恢复,请谨慎操作。',
|
|
56
|
+
defaultTitle: '默认话题',
|
|
55
57
|
saveCurrentMessages: '将当前会话保存为话题',
|
|
56
58
|
searchPlaceholder: '搜索话题...',
|
|
57
59
|
},
|
|
@@ -6,10 +6,10 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
|
7
7
|
import { shallow } from 'zustand/shallow';
|
|
8
8
|
|
|
9
|
-
import { Topic } from '@/pages/chat/[id]/Config/Topic';
|
|
10
9
|
import { agentSelectors, useSessionStore } from '@/store/session';
|
|
11
10
|
|
|
12
11
|
import Header from './Header';
|
|
12
|
+
import { Topic } from './Topic';
|
|
13
13
|
|
|
14
14
|
const useStyles = createStyles(({ css, token }) => ({
|
|
15
15
|
desc: css`
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Icon } from '@lobehub/ui';
|
|
2
|
+
import { Tag, Typography } from 'antd';
|
|
3
|
+
import { useTheme } from 'antd-style';
|
|
4
|
+
import { MessageSquareDashed } from 'lucide-react';
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import { Flexbox } from 'react-layout-kit';
|
|
8
|
+
|
|
9
|
+
const { Paragraph } = Typography;
|
|
10
|
+
|
|
11
|
+
const DefaultContent = memo(() => {
|
|
12
|
+
const { t } = useTranslation('common');
|
|
13
|
+
|
|
14
|
+
const theme = useTheme();
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
18
|
+
<Flexbox align={'center'} height={24} justify={'center'} width={24}>
|
|
19
|
+
<Icon color={theme.colorTextDescription} icon={MessageSquareDashed} />
|
|
20
|
+
</Flexbox>
|
|
21
|
+
<Paragraph ellipsis={{ rows: 1 }} style={{ margin: 0 }}>
|
|
22
|
+
{t('topic.defaultTitle')}
|
|
23
|
+
</Paragraph>
|
|
24
|
+
<Tag>{t('temp')}</Tag>
|
|
25
|
+
</Flexbox>
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export default DefaultContent;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { ActionIcon, EditableText, Icon } from '@lobehub/ui';
|
|
2
|
+
import { App, Dropdown, type MenuProps, Typography } from 'antd';
|
|
3
|
+
import { createStyles } from 'antd-style';
|
|
4
|
+
import { MoreVertical, PencilLine, Star, Trash } from 'lucide-react';
|
|
5
|
+
import { memo, useMemo } from 'react';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import { shallow } from 'zustand/shallow';
|
|
8
|
+
|
|
9
|
+
import { useSessionStore } from '@/store/session';
|
|
10
|
+
|
|
11
|
+
const useStyles = createStyles(({ css }) => ({
|
|
12
|
+
content: css`
|
|
13
|
+
position: relative;
|
|
14
|
+
overflow: hidden;
|
|
15
|
+
flex: 1;
|
|
16
|
+
`,
|
|
17
|
+
title: css`
|
|
18
|
+
flex: 1;
|
|
19
|
+
height: 28px;
|
|
20
|
+
line-height: 28px;
|
|
21
|
+
text-align: start;
|
|
22
|
+
`,
|
|
23
|
+
}));
|
|
24
|
+
const { Paragraph } = Typography;
|
|
25
|
+
|
|
26
|
+
interface TopicContentProps {
|
|
27
|
+
fav?: boolean;
|
|
28
|
+
id: string;
|
|
29
|
+
title: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const TopicContent = memo<TopicContentProps>(({ id, title, fav }) => {
|
|
33
|
+
const { t } = useTranslation('common');
|
|
34
|
+
|
|
35
|
+
const [editing, dispatchTopic, removeTopic] = useSessionStore(
|
|
36
|
+
(s) => [s.renameTopicId === id, s.dispatchTopic, s.removeTopic],
|
|
37
|
+
shallow,
|
|
38
|
+
);
|
|
39
|
+
const { styles, theme } = useStyles();
|
|
40
|
+
|
|
41
|
+
const toggleEditing = (visible?: boolean) => {
|
|
42
|
+
useSessionStore.setState({ renameTopicId: visible ? id : '' });
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const { modal } = App.useApp();
|
|
46
|
+
|
|
47
|
+
const items = useMemo<MenuProps['items']>(
|
|
48
|
+
() => [
|
|
49
|
+
{
|
|
50
|
+
icon: <Icon icon={PencilLine} />,
|
|
51
|
+
key: 'rename',
|
|
52
|
+
label: t('rename'),
|
|
53
|
+
onClick: () => {
|
|
54
|
+
toggleEditing(true);
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
// {
|
|
58
|
+
// icon: <Icon icon={Share2} />,
|
|
59
|
+
// key: 'share',
|
|
60
|
+
// label: t('share'),
|
|
61
|
+
// },
|
|
62
|
+
{
|
|
63
|
+
danger: true,
|
|
64
|
+
icon: <Icon icon={Trash} />,
|
|
65
|
+
key: 'delete',
|
|
66
|
+
label: t('delete'),
|
|
67
|
+
onClick: () => {
|
|
68
|
+
if (!id) return;
|
|
69
|
+
|
|
70
|
+
modal.confirm({
|
|
71
|
+
centered: true,
|
|
72
|
+
okButtonProps: { danger: true },
|
|
73
|
+
onOk: () => {
|
|
74
|
+
removeTopic(id);
|
|
75
|
+
},
|
|
76
|
+
title: t('topic.confirmRemoveTopic'),
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
[],
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<>
|
|
86
|
+
<ActionIcon
|
|
87
|
+
color={fav ? theme.colorWarning : undefined}
|
|
88
|
+
fill={fav ? theme.colorWarning : 'transparent'}
|
|
89
|
+
icon={Star}
|
|
90
|
+
onClick={() => {
|
|
91
|
+
if (!id) return;
|
|
92
|
+
dispatchTopic({ favorite: !fav, id, type: 'favorChatTopic' });
|
|
93
|
+
}}
|
|
94
|
+
size={'small'}
|
|
95
|
+
/>
|
|
96
|
+
|
|
97
|
+
{!editing ? (
|
|
98
|
+
<Paragraph
|
|
99
|
+
className={styles.title}
|
|
100
|
+
ellipsis={{ rows: 1, tooltip: title }}
|
|
101
|
+
style={{ margin: 0 }}
|
|
102
|
+
>
|
|
103
|
+
{title}
|
|
104
|
+
</Paragraph>
|
|
105
|
+
) : (
|
|
106
|
+
<EditableText
|
|
107
|
+
editing={editing}
|
|
108
|
+
onChangeEnd={(v) => {
|
|
109
|
+
if (title !== v) {
|
|
110
|
+
dispatchTopic({ id, key: 'title', type: 'updateChatTopic', value: v });
|
|
111
|
+
}
|
|
112
|
+
toggleEditing(false);
|
|
113
|
+
}}
|
|
114
|
+
onEditingChange={toggleEditing}
|
|
115
|
+
showEditIcon={false}
|
|
116
|
+
size={'small'}
|
|
117
|
+
style={{
|
|
118
|
+
background: theme.colorBgContainer,
|
|
119
|
+
borderRadius: 6,
|
|
120
|
+
height: 28,
|
|
121
|
+
padding: '0 2px',
|
|
122
|
+
}}
|
|
123
|
+
value={title}
|
|
124
|
+
/>
|
|
125
|
+
)}
|
|
126
|
+
{!editing && (
|
|
127
|
+
<Dropdown
|
|
128
|
+
arrow={false}
|
|
129
|
+
menu={{
|
|
130
|
+
items: items,
|
|
131
|
+
onClick: ({ domEvent }) => {
|
|
132
|
+
domEvent.stopPropagation();
|
|
133
|
+
},
|
|
134
|
+
}}
|
|
135
|
+
trigger={['click']}
|
|
136
|
+
>
|
|
137
|
+
<ActionIcon
|
|
138
|
+
className="topic-more"
|
|
139
|
+
icon={MoreVertical}
|
|
140
|
+
onClick={(e) => {
|
|
141
|
+
e.stopPropagation();
|
|
142
|
+
}}
|
|
143
|
+
size={'small'}
|
|
144
|
+
/>
|
|
145
|
+
</Dropdown>
|
|
146
|
+
)}
|
|
147
|
+
</>
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
export default TopicContent;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createStyles } from 'antd-style';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
import { shallow } from 'zustand/shallow';
|
|
5
|
+
|
|
6
|
+
import { useSessionStore } from '@/store/session';
|
|
7
|
+
|
|
8
|
+
import DefaultContent from './DefaultContent';
|
|
9
|
+
import TopicContent from './TopicContent';
|
|
10
|
+
|
|
11
|
+
const useStyles = createStyles(({ css, token, isDarkMode }) => ({
|
|
12
|
+
active: css`
|
|
13
|
+
background: ${isDarkMode ? token.colorFillTertiary : token.colorFillSecondary};
|
|
14
|
+
transition: background 200ms ${token.motionEaseOut};
|
|
15
|
+
|
|
16
|
+
&:hover {
|
|
17
|
+
background: ${token.colorFill};
|
|
18
|
+
}
|
|
19
|
+
`,
|
|
20
|
+
container: css`
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
padding: 12px 8px;
|
|
23
|
+
border-radius: ${token.borderRadius}px;
|
|
24
|
+
|
|
25
|
+
.topic-more {
|
|
26
|
+
opacity: 0;
|
|
27
|
+
transition: opacity 400ms ${token.motionEaseOut};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
&:hover {
|
|
31
|
+
background: ${token.colorFillSecondary};
|
|
32
|
+
|
|
33
|
+
.topic-more {
|
|
34
|
+
opacity: 1;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
`,
|
|
38
|
+
split: css`
|
|
39
|
+
border-bottom: 1px solid ${token.colorSplit};
|
|
40
|
+
`,
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
export interface ConfigCellProps {
|
|
44
|
+
active?: boolean;
|
|
45
|
+
fav?: boolean;
|
|
46
|
+
id?: string;
|
|
47
|
+
title: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const TopicItem = memo<ConfigCellProps>(({ title, active, id, fav }) => {
|
|
51
|
+
const { styles, cx } = useStyles();
|
|
52
|
+
|
|
53
|
+
const [toggleTopic] = useSessionStore((s) => [s.toggleTopic], shallow);
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<Flexbox
|
|
57
|
+
align={'center'}
|
|
58
|
+
className={cx(styles.container, active && styles.active)}
|
|
59
|
+
distribution={'space-between'}
|
|
60
|
+
horizontal
|
|
61
|
+
onClick={() => {
|
|
62
|
+
toggleTopic(id);
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
{!id ? <DefaultContent /> : <TopicContent fav={fav} id={id} title={title} />}
|
|
66
|
+
</Flexbox>
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export default TopicItem;
|
|
@@ -13,14 +13,7 @@ export const Topic = () => {
|
|
|
13
13
|
<TopicItem active={!activeTopicId} fav={false} title={'默认话题'} />
|
|
14
14
|
|
|
15
15
|
{topics.map(({ id, favorite, title }) => (
|
|
16
|
-
<TopicItem
|
|
17
|
-
active={activeTopicId === id}
|
|
18
|
-
fav={favorite}
|
|
19
|
-
id={id}
|
|
20
|
-
key={id}
|
|
21
|
-
showFav
|
|
22
|
-
title={title}
|
|
23
|
-
/>
|
|
16
|
+
<TopicItem active={activeTopicId === id} fav={favorite} id={id} key={id} title={title} />
|
|
24
17
|
))}
|
|
25
18
|
</Flexbox>
|
|
26
19
|
);
|
|
@@ -5,7 +5,7 @@ import { shallow } from 'zustand/shallow';
|
|
|
5
5
|
|
|
6
6
|
import HeaderSpacing from '@/components/HeaderSpacing';
|
|
7
7
|
import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
|
|
8
|
-
import {
|
|
8
|
+
import { useSettings } from '@/store/settings';
|
|
9
9
|
|
|
10
10
|
import SideBar from './SideBar';
|
|
11
11
|
|
|
@@ -23,8 +23,8 @@ const useStyles = createStyles(({ cx, css, token, stylish }) => ({
|
|
|
23
23
|
|
|
24
24
|
const Config = () => {
|
|
25
25
|
const { styles } = useStyles();
|
|
26
|
-
const [showAgentSettings, toggleConfig] =
|
|
27
|
-
(s) => [s.
|
|
26
|
+
const [showAgentSettings, toggleConfig] = useSettings(
|
|
27
|
+
(s) => [s.showAgentConfig, s.toggleAgentPanel],
|
|
28
28
|
shallow,
|
|
29
29
|
);
|
|
30
30
|
|
|
@@ -32,11 +32,9 @@ const Config = () => {
|
|
|
32
32
|
<DraggablePanel
|
|
33
33
|
className={styles.drawer}
|
|
34
34
|
expand={showAgentSettings}
|
|
35
|
-
maxWidth={CHAT_SIDEBAR_WIDTH}
|
|
36
35
|
minWidth={CHAT_SIDEBAR_WIDTH}
|
|
37
36
|
onExpandChange={toggleConfig}
|
|
38
37
|
placement={'right'}
|
|
39
|
-
resize={false}
|
|
40
38
|
>
|
|
41
39
|
<HeaderSpacing />
|
|
42
40
|
<DraggablePanelContainer style={{ flex: 'none', minWidth: CHAT_SIDEBAR_WIDTH }}>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ChatInputArea, DraggablePanel, Icon, Tooltip } from '@lobehub/ui';
|
|
2
2
|
import { Button } from 'antd';
|
|
3
3
|
import { LucideGalleryVerticalEnd } from 'lucide-react';
|
|
4
|
-
import { memo,
|
|
4
|
+
import { memo, useState } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
import { shallow } from 'zustand/shallow';
|
|
7
7
|
|
|
@@ -18,18 +18,15 @@ const ChatInput = () => {
|
|
|
18
18
|
const [text, setText] = useState('');
|
|
19
19
|
|
|
20
20
|
const [inputHeight] = useSettings((s) => [s.inputHeight], shallow);
|
|
21
|
-
const [sendMessage, saveToTopic] = useSessionStore(
|
|
22
|
-
(s) => [s.createOrSendMsg, s.saveToTopic],
|
|
21
|
+
const [sendMessage, hasTopic, saveToTopic] = useSessionStore(
|
|
22
|
+
(s) => [s.createOrSendMsg, !!s.activeTopicId, s.saveToTopic],
|
|
23
23
|
shallow,
|
|
24
24
|
);
|
|
25
25
|
|
|
26
|
-
const footer =
|
|
27
|
-
()
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
</Tooltip>
|
|
31
|
-
),
|
|
32
|
-
[],
|
|
26
|
+
const footer = hasTopic ? null : (
|
|
27
|
+
<Tooltip title={t('topic.saveCurrentMessages')}>
|
|
28
|
+
<Button icon={<Icon icon={LucideGalleryVerticalEnd} />} onClick={saveToTopic} />
|
|
29
|
+
</Tooltip>
|
|
33
30
|
);
|
|
34
31
|
|
|
35
32
|
return (
|
|
@@ -8,6 +8,7 @@ import { shallow } from 'zustand/shallow';
|
|
|
8
8
|
|
|
9
9
|
import HeaderTitle from '@/components/HeaderTitle';
|
|
10
10
|
import { agentSelectors, useSessionStore } from '@/store/session';
|
|
11
|
+
import { useSettings } from '@/store/settings';
|
|
11
12
|
|
|
12
13
|
const Header = memo(() => {
|
|
13
14
|
const { t } = useTranslation('common');
|
|
@@ -24,8 +25,8 @@ const Header = memo(() => {
|
|
|
24
25
|
shallow,
|
|
25
26
|
);
|
|
26
27
|
|
|
27
|
-
const [showAgentSettings, toggleConfig] =
|
|
28
|
-
(s) => [s.
|
|
28
|
+
const [showAgentSettings, toggleConfig] = useSettings(
|
|
29
|
+
(s) => [s.showAgentConfig, s.toggleAgentPanel],
|
|
29
30
|
shallow,
|
|
30
31
|
);
|
|
31
32
|
|
|
@@ -46,11 +46,6 @@ export interface AgentAction {
|
|
|
46
46
|
internalUpdateAgentMeta: (id: string) => any;
|
|
47
47
|
toggleAgentPlugin: (pluginId: string) => void;
|
|
48
48
|
|
|
49
|
-
/**
|
|
50
|
-
* 切换配置
|
|
51
|
-
* @param showPanel - 是否显示面板,默认为 true
|
|
52
|
-
*/
|
|
53
|
-
toggleConfig: (showPanel?: boolean) => void;
|
|
54
49
|
/**
|
|
55
50
|
* 更新代理配置
|
|
56
51
|
* @param config - 部分 LobeAgentConfig 的配置
|
|
@@ -214,12 +209,6 @@ export const createAgentSlice: StateCreator<
|
|
|
214
209
|
get().dispatchSession({ config, id: activeId, type: 'updateSessionConfig' });
|
|
215
210
|
},
|
|
216
211
|
|
|
217
|
-
toggleConfig: (newValue) => {
|
|
218
|
-
const showAgentSettings = typeof newValue === 'boolean' ? newValue : !get().showAgentSettings;
|
|
219
|
-
|
|
220
|
-
set({ showAgentSettings });
|
|
221
|
-
},
|
|
222
|
-
|
|
223
212
|
updateAgentConfig: (config) => {
|
|
224
213
|
const { activeId } = get();
|
|
225
214
|
const session = sessionSelectors.currentSession(get());
|
|
@@ -6,8 +6,6 @@ export type SessionLoadingState = Record<Partial<keyof MetaData>, boolean>;
|
|
|
6
6
|
|
|
7
7
|
export interface AgentConfigState {
|
|
8
8
|
autocompleteLoading: SessionLoadingState;
|
|
9
|
-
|
|
10
|
-
showAgentSettings: boolean;
|
|
11
9
|
}
|
|
12
10
|
|
|
13
11
|
export const initialLobeAgentConfig: LobeAgentConfig = {
|
|
@@ -32,6 +30,4 @@ export const initialAgentConfigState: AgentConfigState = {
|
|
|
32
30
|
tag: false,
|
|
33
31
|
title: false,
|
|
34
32
|
},
|
|
35
|
-
|
|
36
|
-
showAgentSettings: true,
|
|
37
33
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { StateCreator } from 'zustand/vanilla';
|
|
2
2
|
|
|
3
|
+
import { LOADING_FLAT } from '@/const/message';
|
|
3
4
|
import { fetchChatModel } from '@/services/chatModel';
|
|
4
5
|
import { fetchPlugin } from '@/services/plugin';
|
|
5
6
|
import { SessionStore, agentSelectors, chatSelectors, sessionSelectors } from '@/store/session';
|
|
@@ -10,8 +11,6 @@ import { nanoid } from '@/utils/uuid';
|
|
|
10
11
|
|
|
11
12
|
import { MessageDispatch, messagesReducer } from '../reducers/message';
|
|
12
13
|
|
|
13
|
-
const LOADING_FLAT = '...';
|
|
14
|
-
|
|
15
14
|
/**
|
|
16
15
|
* 聊天操作
|
|
17
16
|
*/
|
|
@@ -216,6 +215,7 @@ export const chatMessage: StateCreator<
|
|
|
216
215
|
|
|
217
216
|
await realFetchAIResponse(histories, latestMsg.id);
|
|
218
217
|
},
|
|
218
|
+
|
|
219
219
|
sendMessage: async (message) => {
|
|
220
220
|
const { dispatchMessage, realFetchAIResponse, autocompleteSessionAgentMeta, activeTopicId } =
|
|
221
221
|
get();
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { StateCreator } from 'zustand/vanilla';
|
|
2
2
|
|
|
3
|
+
import { LOADING_FLAT } from '@/const/message';
|
|
3
4
|
import { promptSummaryTitle } from '@/prompts/chat';
|
|
4
|
-
import { SessionStore, chatSelectors, sessionSelectors } from '@/store/session';
|
|
5
|
+
import { SessionStore, chatSelectors, sessionSelectors, topicSelectors } from '@/store/session';
|
|
5
6
|
import { fetchPresetTaskResult } from '@/utils/fetch';
|
|
6
7
|
import { nanoid } from '@/utils/uuid';
|
|
7
8
|
|
|
@@ -13,6 +14,11 @@ export interface ChatTopicAction {
|
|
|
13
14
|
* @param payload - 要分发的主题
|
|
14
15
|
*/
|
|
15
16
|
dispatchTopic: (payload: ChatTopicDispatch) => void;
|
|
17
|
+
/**
|
|
18
|
+
* 移除话题
|
|
19
|
+
* @param id
|
|
20
|
+
*/
|
|
21
|
+
removeTopic: (id: string) => void;
|
|
16
22
|
/**
|
|
17
23
|
* 将当前消息保存为主题
|
|
18
24
|
*/
|
|
@@ -28,6 +34,7 @@ export interface ChatTopicAction {
|
|
|
28
34
|
*/
|
|
29
35
|
updateTopicLoading: (id?: string) => void;
|
|
30
36
|
}
|
|
37
|
+
|
|
31
38
|
export const chatTopic: StateCreator<
|
|
32
39
|
SessionStore,
|
|
33
40
|
[['zustand/devtools', never]],
|
|
@@ -43,6 +50,24 @@ export const chatTopic: StateCreator<
|
|
|
43
50
|
|
|
44
51
|
get().dispatchSession({ id: activeId, topics, type: 'updateSessionTopic' });
|
|
45
52
|
},
|
|
53
|
+
removeTopic: (id) => {
|
|
54
|
+
const { dispatchTopic, dispatchMessage, toggleTopic } = get();
|
|
55
|
+
|
|
56
|
+
// 移除关联的 message
|
|
57
|
+
const messages = topicSelectors.getTopicMessages(id)(get());
|
|
58
|
+
for (const m of messages) {
|
|
59
|
+
dispatchMessage({
|
|
60
|
+
id: m.id,
|
|
61
|
+
type: 'deleteMessage',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 最后移除 topic
|
|
66
|
+
dispatchTopic({ id, type: 'deleteChatTopic' });
|
|
67
|
+
|
|
68
|
+
// 切换到默认 topic
|
|
69
|
+
toggleTopic();
|
|
70
|
+
},
|
|
46
71
|
saveToTopic: () => {
|
|
47
72
|
const session = sessionSelectors.currentSession(get());
|
|
48
73
|
if (!session) return;
|
|
@@ -71,6 +96,8 @@ export const chatTopic: StateCreator<
|
|
|
71
96
|
dispatchMessage({ id: m.id, key: 'topicId', type: 'updateMessage', value: topicId });
|
|
72
97
|
}
|
|
73
98
|
|
|
99
|
+
dispatchTopic({ id: topicId, key: 'title', type: 'updateChatTopic', value: LOADING_FLAT });
|
|
100
|
+
|
|
74
101
|
let output = '';
|
|
75
102
|
|
|
76
103
|
// 自动总结话题标题
|
|
@@ -91,7 +118,6 @@ export const chatTopic: StateCreator<
|
|
|
91
118
|
toggleTopic: (id) => {
|
|
92
119
|
set({ activeTopicId: id });
|
|
93
120
|
},
|
|
94
|
-
|
|
95
121
|
updateTopicLoading: (id) => {
|
|
96
122
|
set({ topicLoadingId: id });
|
|
97
123
|
},
|
|
@@ -14,12 +14,22 @@ interface UpdateChatTopicAction {
|
|
|
14
14
|
value: any;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
interface FavorChatTopicAction {
|
|
18
|
+
favorite: boolean;
|
|
19
|
+
id: string;
|
|
20
|
+
type: 'favorChatTopic';
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
interface DeleteChatTopicAction {
|
|
18
24
|
id: string;
|
|
19
25
|
type: 'deleteChatTopic';
|
|
20
26
|
}
|
|
21
27
|
|
|
22
|
-
export type ChatTopicDispatch =
|
|
28
|
+
export type ChatTopicDispatch =
|
|
29
|
+
| AddChatTopicAction
|
|
30
|
+
| UpdateChatTopicAction
|
|
31
|
+
| DeleteChatTopicAction
|
|
32
|
+
| FavorChatTopicAction;
|
|
23
33
|
|
|
24
34
|
export const topicReducer = (state: ChatTopicMap, payload: ChatTopicDispatch): ChatTopicMap => {
|
|
25
35
|
switch (payload.type) {
|
|
@@ -46,6 +56,18 @@ export const topicReducer = (state: ChatTopicMap, payload: ChatTopicDispatch): C
|
|
|
46
56
|
});
|
|
47
57
|
}
|
|
48
58
|
|
|
59
|
+
case 'favorChatTopic': {
|
|
60
|
+
return produce(state, (draftState) => {
|
|
61
|
+
const { favorite, id } = payload;
|
|
62
|
+
|
|
63
|
+
if (!draftState[id]) return;
|
|
64
|
+
|
|
65
|
+
const topic = draftState[id];
|
|
66
|
+
|
|
67
|
+
topic.favorite = favorite;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
49
71
|
case 'deleteChatTopic': {
|
|
50
72
|
return produce(state, (draftState) => {
|
|
51
73
|
delete draftState[payload.id];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { currentChats } from './chat';
|
|
2
2
|
import { chatsTokenCount, systemRoleTokenCount, totalTokenCount } from './token';
|
|
3
|
-
import { currentTopics } from './topic';
|
|
3
|
+
import { currentTopics, getTopicMessages } from './topic';
|
|
4
4
|
|
|
5
5
|
export const chatSelectors = {
|
|
6
6
|
chatsTokenCount,
|
|
@@ -11,4 +11,5 @@ export const chatSelectors = {
|
|
|
11
11
|
|
|
12
12
|
export const topicSelectors = {
|
|
13
13
|
currentTopics,
|
|
14
|
+
getTopicMessages,
|
|
14
15
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// 展示在聊天框中的消息
|
|
2
2
|
import { SessionStore, sessionSelectors } from '@/store/session';
|
|
3
|
+
import { organizeChats } from '@/store/session/slices/chat/selectors/utils';
|
|
3
4
|
import { ChatTopic } from '@/types/topic';
|
|
4
5
|
|
|
5
6
|
export const currentTopics = (s: SessionStore): ChatTopic[] => {
|
|
@@ -14,3 +15,10 @@ export const currentTopics = (s: SessionStore): ChatTopic[] => {
|
|
|
14
15
|
|
|
15
16
|
return [...favTopics, ...defaultTopics];
|
|
16
17
|
};
|
|
18
|
+
|
|
19
|
+
export const getTopicMessages = (topicId: string) => (s: SessionStore) => {
|
|
20
|
+
const session = sessionSelectors.currentSession(s);
|
|
21
|
+
if (!session) return [];
|
|
22
|
+
|
|
23
|
+
return organizeChats(session, { assistant: '', user: '' }, topicId);
|
|
24
|
+
};
|
|
@@ -36,6 +36,7 @@ export interface SettingsAction {
|
|
|
36
36
|
* @param key - 选中的侧边栏选项
|
|
37
37
|
*/
|
|
38
38
|
switchSideBar: (key: SidebarTabKey) => void;
|
|
39
|
+
toggleAgentPanel: (visible?: boolean) => void;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
export const createSettings: StateCreator<
|
|
@@ -52,7 +53,7 @@ export const createSettings: StateCreator<
|
|
|
52
53
|
setSettings({
|
|
53
54
|
...settings,
|
|
54
55
|
// 如果用户存在用户头像,那么不做导入
|
|
55
|
-
avatar: get().settings.avatar
|
|
56
|
+
avatar: !get().settings.avatar ? settings.avatar : get().settings.avatar,
|
|
56
57
|
});
|
|
57
58
|
},
|
|
58
59
|
resetSettings: () => {
|
|
@@ -71,4 +72,9 @@ export const createSettings: StateCreator<
|
|
|
71
72
|
switchSideBar: (key) => {
|
|
72
73
|
set({ sidebarKey: key });
|
|
73
74
|
},
|
|
75
|
+
toggleAgentPanel: (newValue) => {
|
|
76
|
+
const showAgentConfig = typeof newValue === 'boolean' ? newValue : !get().showAgentConfig;
|
|
77
|
+
|
|
78
|
+
set({ showAgentConfig });
|
|
79
|
+
},
|
|
74
80
|
});
|
|
@@ -31,6 +31,7 @@ export interface SettingsState {
|
|
|
31
31
|
sessionExpandable?: boolean;
|
|
32
32
|
sessionsWidth: number;
|
|
33
33
|
settings: GlobalSettings;
|
|
34
|
+
showAgentConfig?: boolean;
|
|
34
35
|
sidebarKey: SidebarTabKey;
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -39,5 +40,6 @@ export const initialState: SettingsState = {
|
|
|
39
40
|
sessionExpandable: true,
|
|
40
41
|
sessionsWidth: 320,
|
|
41
42
|
settings: DEFAULT_SETTINGS,
|
|
43
|
+
showAgentConfig: true,
|
|
42
44
|
sidebarKey: 'chat',
|
|
43
45
|
};
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { ActionIcon, Icon } from '@lobehub/ui';
|
|
2
|
-
import { Dropdown, type MenuProps, Tag, Typography } from 'antd';
|
|
3
|
-
import { createStyles } from 'antd-style';
|
|
4
|
-
import { MessageSquareDashed, MoreVertical, PencilLine, Share2, Star, Trash } from 'lucide-react';
|
|
5
|
-
import { memo, useMemo, useState } from 'react';
|
|
6
|
-
import { useTranslation } from 'react-i18next';
|
|
7
|
-
import { Flexbox } from 'react-layout-kit';
|
|
8
|
-
import { shallow } from 'zustand/shallow';
|
|
9
|
-
|
|
10
|
-
import { useSessionStore } from '@/store/session';
|
|
11
|
-
|
|
12
|
-
const { Paragraph } = Typography;
|
|
13
|
-
|
|
14
|
-
const useStyles = createStyles(({ css, token, isDarkMode }) => ({
|
|
15
|
-
active: css`
|
|
16
|
-
background: ${isDarkMode ? token.colorFillTertiary : token.colorFillSecondary};
|
|
17
|
-
transition: background 200ms ${token.motionEaseOut};
|
|
18
|
-
|
|
19
|
-
&:hover {
|
|
20
|
-
background: ${token.colorFill};
|
|
21
|
-
}
|
|
22
|
-
`,
|
|
23
|
-
container: css`
|
|
24
|
-
cursor: pointer;
|
|
25
|
-
padding: 12px 8px;
|
|
26
|
-
border-radius: ${token.borderRadius}px;
|
|
27
|
-
|
|
28
|
-
.topic-more {
|
|
29
|
-
opacity: 0;
|
|
30
|
-
transition: opacity 400ms ${token.motionEaseOut};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
&:hover {
|
|
34
|
-
background: ${token.colorFillSecondary};
|
|
35
|
-
|
|
36
|
-
.topic-more {
|
|
37
|
-
opacity: 1;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
`,
|
|
41
|
-
split: css`
|
|
42
|
-
border-bottom: 1px solid ${token.colorSplit};
|
|
43
|
-
`,
|
|
44
|
-
}));
|
|
45
|
-
|
|
46
|
-
export interface ConfigCellProps {
|
|
47
|
-
active?: boolean;
|
|
48
|
-
fav?: boolean;
|
|
49
|
-
id?: string;
|
|
50
|
-
showFav?: boolean;
|
|
51
|
-
title: string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const TopicItem = memo<ConfigCellProps>(({ title, active, id, showFav, fav }) => {
|
|
55
|
-
const [dropdownOpen, setDropdownOpen] = useState(false);
|
|
56
|
-
const { styles, theme, cx } = useStyles();
|
|
57
|
-
const { t } = useTranslation('common');
|
|
58
|
-
|
|
59
|
-
const [dispatchTopic, toggleTopic] = useSessionStore(
|
|
60
|
-
(s) => [s.dispatchTopic, s.toggleTopic],
|
|
61
|
-
shallow,
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
// TODO: 动作绑定
|
|
65
|
-
const items: MenuProps['items'] = useMemo(
|
|
66
|
-
() => [
|
|
67
|
-
{
|
|
68
|
-
icon: <Icon icon={PencilLine} />,
|
|
69
|
-
key: 'rename',
|
|
70
|
-
label: t('rename'),
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
icon: <Icon icon={Share2} />,
|
|
74
|
-
key: 'share',
|
|
75
|
-
label: t('share'),
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
icon: <Icon icon={Trash} />,
|
|
79
|
-
key: 'delete',
|
|
80
|
-
label: t('delete'),
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
[],
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
return (
|
|
87
|
-
<Flexbox
|
|
88
|
-
align={'center'}
|
|
89
|
-
className={cx(styles.container, active && styles.active)}
|
|
90
|
-
distribution={'space-between'}
|
|
91
|
-
horizontal
|
|
92
|
-
onClick={() => {
|
|
93
|
-
toggleTopic(id);
|
|
94
|
-
}}
|
|
95
|
-
>
|
|
96
|
-
<Flexbox align={'center'} gap={8} horizontal>
|
|
97
|
-
{!showFav ? (
|
|
98
|
-
<Flexbox align={'center'} height={24} justify={'center'} width={24}>
|
|
99
|
-
<Icon color={theme.colorTextDescription} icon={MessageSquareDashed} />
|
|
100
|
-
</Flexbox>
|
|
101
|
-
) : (
|
|
102
|
-
<ActionIcon
|
|
103
|
-
color={fav ? theme.colorWarning : undefined}
|
|
104
|
-
fill={fav ? theme.colorWarning : 'transparent'}
|
|
105
|
-
icon={Star}
|
|
106
|
-
onClick={() => {
|
|
107
|
-
if (!id) return;
|
|
108
|
-
dispatchTopic({ id, key: 'favorite', type: 'updateChatTopic', value: !fav });
|
|
109
|
-
}}
|
|
110
|
-
size={'small'}
|
|
111
|
-
/>
|
|
112
|
-
)}
|
|
113
|
-
<Paragraph ellipsis={{ rows: 2 }} style={{ margin: 0 }}>
|
|
114
|
-
{title}
|
|
115
|
-
</Paragraph>
|
|
116
|
-
{id ? '' : <Tag>{t('temp')}</Tag>}
|
|
117
|
-
</Flexbox>
|
|
118
|
-
<Dropdown
|
|
119
|
-
arrow={false}
|
|
120
|
-
menu={{ items }}
|
|
121
|
-
onOpenChange={setDropdownOpen}
|
|
122
|
-
open={dropdownOpen}
|
|
123
|
-
trigger={['click']}
|
|
124
|
-
>
|
|
125
|
-
<ActionIcon
|
|
126
|
-
className="topic-more"
|
|
127
|
-
icon={MoreVertical}
|
|
128
|
-
size={'small'}
|
|
129
|
-
style={dropdownOpen ? { opacity: 1 } : {}}
|
|
130
|
-
/>
|
|
131
|
-
</Dropdown>
|
|
132
|
-
</Flexbox>
|
|
133
|
-
);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
export default TopicItem;
|