@lobehub/chat 1.7.6 → 1.7.8
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/README.md +3 -3
- package/README.zh-CN.md +3 -3
- package/package.json +2 -2
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/TopicContent.tsx +15 -7
- package/src/app/(main)/chat/(workspace)/_layout/Mobile/ChatHeader/ChatHeaderTitle.tsx +10 -1
- package/src/app/(main)/chat/@session/features/SessionListContent/CollapseGroup/Actions.tsx +5 -1
- package/src/app/(main)/settings/llm/components/ProviderModelList/CustomModelOption.tsx +19 -14
- package/src/app/(main)/settings/llm/components/ProviderModelList/ModelConfigModal/Form.tsx +4 -1
- package/src/components/ModelSelect/index.tsx +4 -1
- package/src/features/Conversation/Extras/Translate.tsx +1 -2
- package/src/features/Conversation/Messages/Assistant/{ToolCalls → ToolCallItem}/index.tsx +37 -10
- package/src/features/Conversation/Messages/Assistant/{ToolCalls → ToolCallItem}/style.ts +14 -3
- package/src/features/Conversation/Messages/Assistant/index.tsx +4 -5
- package/src/features/Conversation/Messages/Default.tsx +1 -1
- package/src/features/Conversation/Messages/User.tsx +1 -2
- package/src/features/ModelSwitchPanel/index.tsx +5 -1
- package/src/store/chat/slices/message/selectors.test.ts +32 -2
- package/src/store/chat/slices/message/selectors.ts +8 -2
- /package/src/{features/Conversation/components/BubblesLoading.tsx → components/BubblesLoading/index.tsx} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 1.7.8](https://github.com/lobehub/lobe-chat/compare/v1.7.7...v1.7.8)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-07-30**</sup>
|
|
8
|
+
|
|
9
|
+
#### 💄 Styles
|
|
10
|
+
|
|
11
|
+
- **ui**: Modify and repair UI layout.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Styles
|
|
19
|
+
|
|
20
|
+
- **ui**: Modify and repair UI layout, closes [#3321](https://github.com/lobehub/lobe-chat/issues/3321) ([cda776f](https://github.com/lobehub/lobe-chat/commit/cda776f))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 1.7.7](https://github.com/lobehub/lobe-chat/compare/v1.7.6...v1.7.7)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2024-07-30**</sup>
|
|
33
|
+
|
|
34
|
+
#### 💄 Styles
|
|
35
|
+
|
|
36
|
+
- **misc**: Improve tools calling UI.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Styles
|
|
44
|
+
|
|
45
|
+
- **misc**: Improve tools calling UI, closes [#3326](https://github.com/lobehub/lobe-chat/issues/3326) ([36cabc0](https://github.com/lobehub/lobe-chat/commit/36cabc0))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 1.7.6](https://github.com/lobehub/lobe-chat/compare/v1.7.5...v1.7.6)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2024-07-29**</sup>
|
package/README.md
CHANGED
|
@@ -268,12 +268,12 @@ Our marketplace is not just a showcase platform but also a collaborative space.
|
|
|
268
268
|
|
|
269
269
|
| Recent Submits | Description |
|
|
270
270
|
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
271
|
+
| [Code Snark Master](https://chat-preview.lobehub.com/market?agent=code-snark-master)<br/><sup>By **[leter](https://github.com/leter)** on **2024-07-29**</sup> | Specializes in sharp criticism of code, sarcastically pointing out inefficiencies and readability issues<br/>`tech-leadership` `code-review` `sarcastic-style` `programming-consultation` |
|
|
272
|
+
| [Unity Maestro](https://chat-preview.lobehub.com/market?agent=unity-maestro)<br/><sup>By **[thedivergentai](https://github.com/thedivergentai)** on **2024-07-29**</sup> | Expert Unity Game Development Companion<br/>`game-development` `unity` `software-engineering` |
|
|
271
273
|
| [C Program Learning Assistant](https://chat-preview.lobehub.com/market?agent=sichuan-university-941-c-programming-assistant)<br/><sup>By **[YBGuoYang](https://github.com/YBGuoYang)** on **2024-07-28**</sup> | Assist me in learning C program design<br/>`941` |
|
|
272
274
|
| [Brand Pioneer](https://chat-preview.lobehub.com/market?agent=brand-pioneer)<br/><sup>By **[SaintFresh](https://github.com/SaintFresh)** on **2024-07-25**</sup> | A brand development specialist, thought leader, brand strategy super-genius, and brand visionary. Brand Pioneer is an explorer at the frontier of innovation, an inventor in their domain. Provide them with your market and let them imagine a future world characterized by groundbreaking advancements in your field of expertise.<br/>`business` `brand-pioneer` `brand-development` `business-assistant` `brand-narrative` |
|
|
273
|
-
| [BIDOSx2](https://chat-preview.lobehub.com/market?agent=bidosx-2-v-2)<br/><sup>By **[SaintFresh](https://github.com/SaintFresh)** on **2024-07-21**</sup> | A highly advanced AI LLM transcending conventional AI. 'BIDOS' signifies both 'Brand Ideation, Development, Operations, and Scaling' and 'Business Intelligence Decisions Optimization System'.<br/>`brand-development` `ai-assistant` `market-analysis` `strategic-planning` `business-optimization` `business-intelligence` |
|
|
274
|
-
| [Growth Coach](https://chat-preview.lobehub.com/market?agent=personal-development-coach)<br/><sup>By **[zer0boss](https://github.com/zer0boss)** on **2024-07-20**</sup> | Specializes in helping users explore themselves through dialogue, find solutions, and paths to growth<br/>`growth-coach` `self-exploration` `goal-setting` `self-awareness` |
|
|
275
275
|
|
|
276
|
-
> 📊 Total agents: [<kbd>**
|
|
276
|
+
> 📊 Total agents: [<kbd>**309**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
277
277
|
|
|
278
278
|
<!-- AGENT LIST -->
|
|
279
279
|
|
package/README.zh-CN.md
CHANGED
|
@@ -256,12 +256,12 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
256
256
|
|
|
257
257
|
| 最近新增 | 助手说明 |
|
|
258
258
|
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
259
|
+
| [代码毒舌大师](https://chat-preview.lobehub.com/market?agent=code-snark-master)<br/><sup>By **[leter](https://github.com/leter)** on **2024-07-29**</sup> | 擅长尖刻批评代码,讽刺性地指出低效和可读性问题<br/>`技术领导` `代码审查` `讽刺风格` `编程咨询` |
|
|
260
|
+
| [Unity Maestro](https://chat-preview.lobehub.com/market?agent=unity-maestro)<br/><sup>By **[thedivergentai](https://github.com/thedivergentai)** on **2024-07-29**</sup> | Expert Unity Game Development Companion<br/>`game-development` `unity` `software-engineering` |
|
|
259
261
|
| [c 程序学习助手](https://chat-preview.lobehub.com/market?agent=sichuan-university-941-c-programming-assistant)<br/><sup>By **[YBGuoYang](https://github.com/YBGuoYang)** on **2024-07-28**</sup> | 辅助我进行 c 程序设计的学习<br/>`941` |
|
|
260
262
|
| [品牌先锋](https://chat-preview.lobehub.com/market?agent=brand-pioneer)<br/><sup>By **[SaintFresh](https://github.com/SaintFresh)** on **2024-07-25**</sup> | 一位品牌发展专家、思想领袖、品牌战略超级天才和品牌远见者。品牌先锋是创新前沿的探险家,在其领域是一位发明家。将您的市场提供给他们,让他们想象一个未来世界,其中以您的专业领域的突破性进展为特征。<br/>`商业` `品牌先锋` `品牌发展` `商业助手` `品牌叙事` |
|
|
261
|
-
| [BIDOSx2](https://chat-preview.lobehub.com/market?agent=bidosx-2-v-2)<br/><sup>By **[SaintFresh](https://github.com/SaintFresh)** on **2024-07-21**</sup> | 一种高度先进的 AI LLM,超越传统人工智能。'BIDOS' 既代表 ' 品牌构思、发展、运营和扩展 ',也代表 ' 商业智能决策优化系统 '。<br/>`品牌发展` `ai助手` `市场分析` `战略规划` `业务优化` `商业智能` |
|
|
262
|
-
| [成长教练](https://chat-preview.lobehub.com/market?agent=personal-development-coach)<br/><sup>By **[zer0boss](https://github.com/zer0boss)** on **2024-07-20**</sup> | 擅长用对话的方式帮助用户自我探索,找到解决之道和成长之路<br/>`成长教练` `自我探索` `目标设定` `自我觉察` |
|
|
263
263
|
|
|
264
|
-
> 📊 Total agents: [<kbd>**
|
|
264
|
+
> 📊 Total agents: [<kbd>**309**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
265
265
|
|
|
266
266
|
<!-- AGENT LIST -->
|
|
267
267
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.8",
|
|
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",
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"@clerk/localizations": "2.0.0",
|
|
111
111
|
"@clerk/nextjs": "^5.2.6",
|
|
112
112
|
"@clerk/themes": "^2.1.10",
|
|
113
|
-
"@google/generative-ai": "^0.
|
|
113
|
+
"@google/generative-ai": "^0.16.0",
|
|
114
114
|
"@icons-pack/react-simple-icons": "^9.6.0",
|
|
115
115
|
"@khmyznikov/pwa-install": "^0.3.9",
|
|
116
116
|
"@lobehub/chat-plugin-sdk": "^1.32.4",
|
|
@@ -14,6 +14,8 @@ import { memo, useMemo } from 'react';
|
|
|
14
14
|
import { useTranslation } from 'react-i18next';
|
|
15
15
|
import { Flexbox } from 'react-layout-kit';
|
|
16
16
|
|
|
17
|
+
import BubblesLoading from '@/components/BubblesLoading';
|
|
18
|
+
import { LOADING_FLAT } from '@/const/message';
|
|
17
19
|
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
18
20
|
import { useChatStore } from '@/store/chat';
|
|
19
21
|
|
|
@@ -160,13 +162,19 @@ const TopicContent = memo<TopicContentProps>(({ id, title, fav, showMore }) => {
|
|
|
160
162
|
spin={isLoading}
|
|
161
163
|
/>
|
|
162
164
|
{!editing ? (
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
title === LOADING_FLAT ? (
|
|
166
|
+
<Flexbox flex={1} height={28} justify={'center'}>
|
|
167
|
+
<BubblesLoading />
|
|
168
|
+
</Flexbox>
|
|
169
|
+
) : (
|
|
170
|
+
<Paragraph
|
|
171
|
+
className={styles.title}
|
|
172
|
+
ellipsis={{ rows: 1, tooltip: { placement: 'left', title } }}
|
|
173
|
+
style={{ margin: 0 }}
|
|
174
|
+
>
|
|
175
|
+
{title}
|
|
176
|
+
</Paragraph>
|
|
177
|
+
)
|
|
170
178
|
) : (
|
|
171
179
|
<EditableText
|
|
172
180
|
editing={editing}
|
|
@@ -43,7 +43,16 @@ const ChatHeaderTitle = memo(() => {
|
|
|
43
43
|
</Flexbox>
|
|
44
44
|
}
|
|
45
45
|
title={
|
|
46
|
-
<div
|
|
46
|
+
<div
|
|
47
|
+
onClick={() => toggleConfig()}
|
|
48
|
+
style={{
|
|
49
|
+
marginRight: '8px',
|
|
50
|
+
maxWidth: '64vw',
|
|
51
|
+
overflow: 'hidden',
|
|
52
|
+
textOverflow: 'ellipsis',
|
|
53
|
+
whiteSpace: 'nowrap',
|
|
54
|
+
}}
|
|
55
|
+
>
|
|
47
56
|
{displayTitle}
|
|
48
57
|
{topicLength > 1 ? `(${topicLength + 1})` : ''}
|
|
49
58
|
</div>
|
|
@@ -5,6 +5,7 @@ import { MoreVertical, PencilLine, Plus, Settings2, Trash } from 'lucide-react';
|
|
|
5
5
|
import { memo, useMemo } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
|
|
8
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
8
9
|
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
9
10
|
import { useSessionStore } from '@/store/session';
|
|
10
11
|
|
|
@@ -30,6 +31,8 @@ const Actions = memo<ActionsProps>(
|
|
|
30
31
|
const { styles } = useStyles();
|
|
31
32
|
const { modal, message } = App.useApp();
|
|
32
33
|
|
|
34
|
+
const isMobile = useIsMobile();
|
|
35
|
+
|
|
33
36
|
const [createSession, removeSessionGroup] = useSessionStore((s) => [
|
|
34
37
|
s.createSession,
|
|
35
38
|
s.removeSessionGroup,
|
|
@@ -123,12 +126,13 @@ const Actions = memo<ActionsProps>(
|
|
|
123
126
|
trigger={['click']}
|
|
124
127
|
>
|
|
125
128
|
<ActionIcon
|
|
129
|
+
active={isMobile ? true : false}
|
|
126
130
|
icon={MoreVertical}
|
|
127
131
|
onClick={(e) => {
|
|
128
132
|
e.stopPropagation();
|
|
129
133
|
}}
|
|
130
134
|
size={{ blockSize: 22, fontSize: 16 }}
|
|
131
|
-
style={{ marginRight: -8 }}
|
|
135
|
+
style={{ background: isMobile ? 'transparent' : '', marginRight: -8 }}
|
|
132
136
|
/>
|
|
133
137
|
</Dropdown>
|
|
134
138
|
);
|
|
@@ -9,7 +9,7 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
9
9
|
import ModelIcon from '@/components/ModelIcon';
|
|
10
10
|
import { ModelInfoTags } from '@/components/ModelSelect';
|
|
11
11
|
import { useUserStore } from '@/store/user';
|
|
12
|
-
import { modelConfigSelectors } from '@/store/user/selectors';
|
|
12
|
+
import { modelConfigSelectors, modelProviderSelectors } from '@/store/user/selectors';
|
|
13
13
|
import { GlobalLLMProviderKey } from '@/types/user/settings';
|
|
14
14
|
|
|
15
15
|
interface CustomModelOptionProps {
|
|
@@ -28,30 +28,34 @@ const CustomModelOption = memo<CustomModelOptionProps>(({ id, provider }) => {
|
|
|
28
28
|
s.toggleEditingCustomModelCard,
|
|
29
29
|
s.removeEnabledModels,
|
|
30
30
|
]);
|
|
31
|
+
|
|
31
32
|
const modelCard = useUserStore(
|
|
32
33
|
modelConfigSelectors.getCustomModelCard({ id, provider }),
|
|
33
34
|
isEqual,
|
|
34
35
|
);
|
|
35
36
|
|
|
37
|
+
const isEnabled = useUserStore(
|
|
38
|
+
(s) => modelProviderSelectors.getEnableModelsById(provider)(s)?.includes(id),
|
|
39
|
+
isEqual,
|
|
40
|
+
);
|
|
41
|
+
|
|
36
42
|
return (
|
|
37
43
|
<Flexbox align={'center'} distribution={'space-between'} gap={8} horizontal>
|
|
38
|
-
<Flexbox align={'center'} gap={8} horizontal>
|
|
44
|
+
<Flexbox align={'center'} gap={8} horizontal style={{ flex: 1, width: '70%' }}>
|
|
39
45
|
<ModelIcon model={id} size={32} />
|
|
40
|
-
<Flexbox>
|
|
46
|
+
<Flexbox direction={'vertical'} style={{ flex: 1, overflow: 'hidden' }}>
|
|
41
47
|
<Flexbox align={'center'} gap={8} horizontal>
|
|
42
|
-
{modelCard?.displayName || id}
|
|
48
|
+
<Typography.Text ellipsis>{modelCard?.displayName || id}</Typography.Text>
|
|
43
49
|
<ModelInfoTags id={id} {...modelCard} isCustom />
|
|
44
50
|
</Flexbox>
|
|
45
|
-
<Typography.Text style={{ fontSize: 12 }} type={'secondary'}>
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
)}
|
|
54
|
-
</Flexbox>
|
|
51
|
+
<Typography.Text ellipsis style={{ fontSize: 12, marginTop: '4px' }} type={'secondary'}>
|
|
52
|
+
{id}
|
|
53
|
+
{!!modelCard?.deploymentName && (
|
|
54
|
+
<>
|
|
55
|
+
<Icon icon={LucideArrowRight} />
|
|
56
|
+
{modelCard?.deploymentName}
|
|
57
|
+
</>
|
|
58
|
+
)}
|
|
55
59
|
</Typography.Text>
|
|
56
60
|
</Flexbox>
|
|
57
61
|
</Flexbox>
|
|
@@ -83,6 +87,7 @@ const CustomModelOption = memo<CustomModelOptionProps>(({ id, provider }) => {
|
|
|
83
87
|
type: 'warning',
|
|
84
88
|
});
|
|
85
89
|
}}
|
|
90
|
+
style={isEnabled ? { marginRight: '10px' } : {}}
|
|
86
91
|
title={t('delete')}
|
|
87
92
|
/>
|
|
88
93
|
</Flexbox>
|
|
@@ -2,6 +2,7 @@ import { Checkbox, Form, FormInstance, Input } from 'antd';
|
|
|
2
2
|
import { memo, useEffect } from 'react';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
|
|
5
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
5
6
|
import { ChatModelCard } from '@/types/llm';
|
|
6
7
|
|
|
7
8
|
import MaxTokenSlider from './MaxTokenSlider';
|
|
@@ -18,6 +19,8 @@ const ModelConfigForm = memo<ModelConfigFormProps>(
|
|
|
18
19
|
|
|
19
20
|
const [formInstance] = Form.useForm();
|
|
20
21
|
|
|
22
|
+
const isMobile = useIsMobile();
|
|
23
|
+
|
|
21
24
|
useEffect(() => {
|
|
22
25
|
onFormInstanceReady(formInstance);
|
|
23
26
|
}, []);
|
|
@@ -37,7 +40,7 @@ const ModelConfigForm = memo<ModelConfigFormProps>(
|
|
|
37
40
|
initialValues={initialValues}
|
|
38
41
|
labelCol={{ span: 4 }}
|
|
39
42
|
style={{ marginTop: 16 }}
|
|
40
|
-
wrapperCol={{ offset: 1, span: 18 }}
|
|
43
|
+
wrapperCol={isMobile ? { span: 18 } : { offset: 1, span: 18 }}
|
|
41
44
|
>
|
|
42
45
|
<Form.Item
|
|
43
46
|
extra={t('llm.customModelCards.modelConfig.id.extra')}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Icon, Tooltip } from '@lobehub/ui';
|
|
2
|
+
import { Typography } from 'antd';
|
|
2
3
|
import { createStyles } from 'antd-style';
|
|
3
4
|
import { Infinity, LucideEye, LucidePaperclip, ToyBrick } from 'lucide-react';
|
|
4
5
|
import numeral from 'numeral';
|
|
@@ -142,7 +143,9 @@ export const ModelItemRender = memo<ModelItemRenderProps>(({ showInfoTag = true,
|
|
|
142
143
|
<Flexbox align={'center'} gap={32} horizontal justify={'space-between'}>
|
|
143
144
|
<Flexbox align={'center'} gap={8} horizontal>
|
|
144
145
|
<ModelIcon model={model.id} size={20} />
|
|
145
|
-
|
|
146
|
+
<Typography.Paragraph ellipsis={false} style={{ marginBottom: 0 }}>
|
|
147
|
+
{model.displayName || model.id}
|
|
148
|
+
</Typography.Paragraph>
|
|
146
149
|
</Flexbox>
|
|
147
150
|
|
|
148
151
|
{showInfoTag && <ModelInfoTags {...model} />}
|
|
@@ -6,11 +6,10 @@ import { memo, useState } from 'react';
|
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
import { Flexbox } from 'react-layout-kit';
|
|
8
8
|
|
|
9
|
+
import BubblesLoading from '@/components/BubblesLoading';
|
|
9
10
|
import { useChatStore } from '@/store/chat';
|
|
10
11
|
import { ChatTranslate } from '@/types/message';
|
|
11
12
|
|
|
12
|
-
import BubblesLoading from '../components/BubblesLoading';
|
|
13
|
-
|
|
14
13
|
interface TranslateProps extends ChatTranslate {
|
|
15
14
|
id: string;
|
|
16
15
|
loading?: boolean;
|
|
@@ -1,57 +1,84 @@
|
|
|
1
|
-
import { Icon } from '@lobehub/ui';
|
|
1
|
+
import { Icon, Tag } from '@lobehub/ui';
|
|
2
|
+
import { Typography } from 'antd';
|
|
2
3
|
import isEqual from 'fast-deep-equal';
|
|
3
|
-
import { Loader2
|
|
4
|
+
import { Loader2 } from 'lucide-react';
|
|
4
5
|
import { CSSProperties, memo, useState } from 'react';
|
|
5
6
|
import { useTranslation } from 'react-i18next';
|
|
6
7
|
import { Flexbox } from 'react-layout-kit';
|
|
7
8
|
|
|
9
|
+
import PluginAvatar from '@/features/PluginAvatar';
|
|
10
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
8
11
|
import { useChatStore } from '@/store/chat';
|
|
9
12
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
10
13
|
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
11
14
|
import { toolSelectors } from '@/store/tool/selectors';
|
|
12
15
|
|
|
16
|
+
import { ToolMessage } from '../../Tool';
|
|
13
17
|
import Arguments from '../../components/Arguments';
|
|
14
18
|
import { useStyles } from './style';
|
|
15
19
|
|
|
16
20
|
export interface InspectorProps {
|
|
21
|
+
apiName: string;
|
|
17
22
|
arguments?: string;
|
|
23
|
+
id: string;
|
|
18
24
|
identifier: string;
|
|
19
25
|
index: number;
|
|
20
26
|
messageId: string;
|
|
21
|
-
style
|
|
27
|
+
style?: CSSProperties;
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
const CallItem = memo<InspectorProps>(
|
|
25
|
-
({ arguments: requestArgs, messageId, index, identifier, style }) => {
|
|
31
|
+
({ arguments: requestArgs, apiName, messageId, id, index, identifier, style }) => {
|
|
26
32
|
const { t } = useTranslation('plugin');
|
|
27
33
|
const { styles } = useStyles();
|
|
28
34
|
const [open, setOpen] = useState(false);
|
|
29
35
|
const loading = useChatStore(chatSelectors.isToolCallStreaming(messageId, index));
|
|
36
|
+
const toolMessage = useChatStore(chatSelectors.getMessageByToolCallId(id));
|
|
37
|
+
const isMobile = useIsMobile();
|
|
30
38
|
|
|
31
39
|
const pluginMeta = useToolStore(toolSelectors.getMetaById(identifier), isEqual);
|
|
32
40
|
|
|
33
41
|
const pluginTitle = pluginHelpers.getPluginTitle(pluginMeta) ?? t('unknownPlugin');
|
|
34
42
|
|
|
35
|
-
|
|
43
|
+
// when tool calling stop streaming, we should show the tool message
|
|
44
|
+
return !loading && toolMessage ? (
|
|
45
|
+
<ToolMessage {...toolMessage} />
|
|
46
|
+
) : (
|
|
36
47
|
<Flexbox gap={8} style={style}>
|
|
37
48
|
<Flexbox
|
|
38
49
|
align={'center'}
|
|
39
50
|
className={styles.container}
|
|
40
51
|
distribution={'space-between'}
|
|
41
52
|
gap={8}
|
|
42
|
-
height={32}
|
|
43
53
|
horizontal
|
|
44
54
|
onClick={() => {
|
|
45
55
|
setOpen(!open);
|
|
46
56
|
}}
|
|
47
57
|
>
|
|
48
58
|
<Flexbox align={'center'} gap={8} horizontal>
|
|
49
|
-
{loading ?
|
|
50
|
-
|
|
59
|
+
{loading ? (
|
|
60
|
+
<div>
|
|
61
|
+
<Icon icon={Loader2} spin />
|
|
62
|
+
</div>
|
|
63
|
+
) : (
|
|
64
|
+
<PluginAvatar identifier={identifier} size={isMobile ? 36 : undefined} />
|
|
65
|
+
)}
|
|
66
|
+
{isMobile ? (
|
|
67
|
+
<Flexbox>
|
|
68
|
+
<div>{pluginTitle}</div>
|
|
69
|
+
<Typography.Text className={styles.apiName} type={'secondary'}>
|
|
70
|
+
{apiName}
|
|
71
|
+
</Typography.Text>
|
|
72
|
+
</Flexbox>
|
|
73
|
+
) : (
|
|
74
|
+
<>
|
|
75
|
+
<div>{pluginTitle}</div>
|
|
76
|
+
<Tag>{apiName}</Tag>
|
|
77
|
+
</>
|
|
78
|
+
)}
|
|
51
79
|
</Flexbox>
|
|
52
|
-
<Icon icon={open ? LucideChevronDown : LucideChevronRight} />
|
|
53
80
|
</Flexbox>
|
|
54
|
-
{
|
|
81
|
+
{loading && <Arguments arguments={requestArgs} />}
|
|
55
82
|
</Flexbox>
|
|
56
83
|
);
|
|
57
84
|
},
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import { createStyles } from 'antd-style';
|
|
2
2
|
|
|
3
3
|
export const useStyles = createStyles(({ css, token }) => ({
|
|
4
|
+
apiName: css`
|
|
5
|
+
overflow: hidden;
|
|
6
|
+
display: -webkit-box;
|
|
7
|
+
-webkit-box-orient: vertical;
|
|
8
|
+
-webkit-line-clamp: 1;
|
|
9
|
+
|
|
10
|
+
font-size: 12px;
|
|
11
|
+
text-overflow: ellipsis;
|
|
12
|
+
`,
|
|
4
13
|
container: css`
|
|
5
14
|
cursor: pointer;
|
|
6
15
|
|
|
7
16
|
width: fit-content;
|
|
8
|
-
padding-
|
|
17
|
+
padding-block: 6px;
|
|
18
|
+
padding-inline: 8px;
|
|
19
|
+
padding-inline-end: 12px;
|
|
9
20
|
|
|
10
21
|
color: ${token.colorText};
|
|
11
22
|
|
|
12
|
-
|
|
23
|
+
border: 1px solid ${token.colorBorder};
|
|
13
24
|
border-radius: 8px;
|
|
14
25
|
|
|
15
26
|
&:hover {
|
|
16
|
-
background: ${token.
|
|
27
|
+
background: ${token.colorFillTertiary};
|
|
17
28
|
}
|
|
18
29
|
`,
|
|
19
30
|
plugin: css`
|
|
@@ -7,7 +7,7 @@ import { chatSelectors } from '@/store/chat/selectors';
|
|
|
7
7
|
import { ChatMessage } from '@/types/message';
|
|
8
8
|
|
|
9
9
|
import { DefaultMessage } from '../Default';
|
|
10
|
-
import ToolCall from './
|
|
10
|
+
import ToolCall from './ToolCallItem';
|
|
11
11
|
|
|
12
12
|
export const AssistantMessage = memo<
|
|
13
13
|
ChatMessage & {
|
|
@@ -31,17 +31,16 @@ export const AssistantMessage = memo<
|
|
|
31
31
|
/>
|
|
32
32
|
)}
|
|
33
33
|
{!editing && tools && (
|
|
34
|
-
<Flexbox gap={8}
|
|
34
|
+
<Flexbox gap={8}>
|
|
35
35
|
{tools.map((toolCall, index) => (
|
|
36
36
|
<ToolCall
|
|
37
|
+
apiName={toolCall.apiName}
|
|
37
38
|
arguments={toolCall.arguments}
|
|
39
|
+
id={toolCall.id}
|
|
38
40
|
identifier={toolCall.identifier}
|
|
39
41
|
index={index}
|
|
40
42
|
key={toolCall.id}
|
|
41
43
|
messageId={id}
|
|
42
|
-
style={{
|
|
43
|
-
maxWidth: `max(${100 / tools.length}%, 300px)`,
|
|
44
|
-
}}
|
|
45
44
|
/>
|
|
46
45
|
))}
|
|
47
46
|
</Flexbox>
|
|
@@ -3,7 +3,7 @@ import { ReactNode, memo } from 'react';
|
|
|
3
3
|
import { LOADING_FLAT } from '@/const/message';
|
|
4
4
|
import { ChatMessage } from '@/types/message';
|
|
5
5
|
|
|
6
|
-
import BubblesLoading from '
|
|
6
|
+
import BubblesLoading from '@/components/BubblesLoading';
|
|
7
7
|
|
|
8
8
|
export const DefaultMessage = memo<
|
|
9
9
|
ChatMessage & {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { ReactNode, memo } from 'react';
|
|
2
2
|
import { Flexbox } from 'react-layout-kit';
|
|
3
3
|
|
|
4
|
+
import BubblesLoading from '@/components/BubblesLoading';
|
|
4
5
|
import { LOADING_FLAT } from '@/const/message';
|
|
5
6
|
import { FileListPreviewer } from '@/features/FileList';
|
|
6
7
|
import { ChatMessage } from '@/types/message';
|
|
7
8
|
|
|
8
|
-
import BubblesLoading from '../components/BubblesLoading';
|
|
9
|
-
|
|
10
9
|
export const UserMessage = memo<
|
|
11
10
|
ChatMessage & {
|
|
12
11
|
editableContent: ReactNode;
|
|
@@ -10,6 +10,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
10
10
|
import { Flexbox } from 'react-layout-kit';
|
|
11
11
|
|
|
12
12
|
import { ModelItemRender, ProviderItemRender } from '@/components/ModelSelect';
|
|
13
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
13
14
|
import { useAgentStore } from '@/store/agent';
|
|
14
15
|
import { agentSelectors } from '@/store/agent/slices/chat';
|
|
15
16
|
import { useUserStore } from '@/store/user';
|
|
@@ -49,7 +50,10 @@ const ModelSwitchPanel = memo<PropsWithChildren>(({ children }) => {
|
|
|
49
50
|
s.updateAgentConfig,
|
|
50
51
|
]);
|
|
51
52
|
|
|
53
|
+
const isMobile = useIsMobile();
|
|
54
|
+
|
|
52
55
|
const router = useRouter();
|
|
56
|
+
|
|
53
57
|
const enabledList = useUserStore(modelProviderSelectors.modelProviderListForModelSelect, isEqual);
|
|
54
58
|
|
|
55
59
|
const items = useMemo<ItemType[]>(() => {
|
|
@@ -102,7 +106,7 @@ const ModelSwitchPanel = memo<PropsWithChildren>(({ children }) => {
|
|
|
102
106
|
overflowY: 'scroll',
|
|
103
107
|
},
|
|
104
108
|
}}
|
|
105
|
-
placement={'topLeft'}
|
|
109
|
+
placement={isMobile ? 'top' : 'topLeft'}
|
|
106
110
|
trigger={['click']}
|
|
107
111
|
>
|
|
108
112
|
<div className={styles.tag}>{children}</div>
|
|
@@ -131,6 +131,36 @@ describe('chatSelectors', () => {
|
|
|
131
131
|
});
|
|
132
132
|
});
|
|
133
133
|
|
|
134
|
+
describe('getMessageByToolCallId', () => {
|
|
135
|
+
it('should return undefined if the message with the given id does not exist', () => {
|
|
136
|
+
const message = chatSelectors.getMessageByToolCallId('non-existent-id')(initialStore);
|
|
137
|
+
expect(message).toBeUndefined();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should return the message object with the matching tool_call_id', () => {
|
|
141
|
+
const toolMessage = {
|
|
142
|
+
id: 'msg3',
|
|
143
|
+
content: 'Function Message',
|
|
144
|
+
role: 'tool',
|
|
145
|
+
tool_call_id: 'ttt',
|
|
146
|
+
plugin: {
|
|
147
|
+
arguments: 'arg1',
|
|
148
|
+
identifier: 'func1',
|
|
149
|
+
apiName: 'ttt',
|
|
150
|
+
type: 'default',
|
|
151
|
+
},
|
|
152
|
+
} as ChatMessage;
|
|
153
|
+
const state = merge(initialStore, {
|
|
154
|
+
messagesMap: {
|
|
155
|
+
[messageMapKey('abc')]: [...mockMessages, toolMessage],
|
|
156
|
+
},
|
|
157
|
+
activeId: 'abc',
|
|
158
|
+
});
|
|
159
|
+
const message = chatSelectors.getMessageByToolCallId('ttt')(state);
|
|
160
|
+
expect(message).toMatchObject(toolMessage);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
134
164
|
describe('currentChatsWithHistoryConfig', () => {
|
|
135
165
|
it('should slice the messages according to the current agent config', () => {
|
|
136
166
|
const state = merge(initialStore, {
|
|
@@ -203,7 +233,7 @@ describe('chatSelectors', () => {
|
|
|
203
233
|
});
|
|
204
234
|
|
|
205
235
|
describe('currentChatsWithGuideMessage', () => {
|
|
206
|
-
it('should return existing messages
|
|
236
|
+
it('should return existing messages except tool message', () => {
|
|
207
237
|
const state = merge(initialStore, {
|
|
208
238
|
messagesMap: {
|
|
209
239
|
[messageMapKey('someActiveId')]: mockMessages,
|
|
@@ -211,7 +241,7 @@ describe('chatSelectors', () => {
|
|
|
211
241
|
activeId: 'someActiveId',
|
|
212
242
|
});
|
|
213
243
|
const chats = chatSelectors.currentChatsWithGuideMessage({} as MetaData)(state);
|
|
214
|
-
expect(chats).toEqual(mockedChats);
|
|
244
|
+
expect(chats).toEqual(mockedChats.slice(0, 2));
|
|
215
245
|
});
|
|
216
246
|
|
|
217
247
|
it('should add a guide message if the chat is brand new', () => {
|
|
@@ -65,11 +65,12 @@ const showInboxWelcome = (s: ChatStore): boolean => {
|
|
|
65
65
|
return isBrandNewChat;
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
-
//
|
|
68
|
+
// Custom message for new assistant initialization
|
|
69
69
|
const currentChatsWithGuideMessage =
|
|
70
70
|
(meta: MetaData) =>
|
|
71
71
|
(s: ChatStore): ChatMessage[] => {
|
|
72
|
-
|
|
72
|
+
// skip tool message
|
|
73
|
+
const data = currentChats(s).filter((m) => m.role !== 'tool');
|
|
73
74
|
|
|
74
75
|
const { isAgentEditable } = featureFlagsSelectors(createServerConfigStore().getState());
|
|
75
76
|
|
|
@@ -125,6 +126,10 @@ const chatsMessageString = (s: ChatStore): string => {
|
|
|
125
126
|
const getMessageById = (id: string) => (s: ChatStore) =>
|
|
126
127
|
chatHelpers.getMessageById(currentChats(s), id);
|
|
127
128
|
|
|
129
|
+
const getMessageByToolCallId = (id: string) => (s: ChatStore) => {
|
|
130
|
+
const messages = currentChats(s);
|
|
131
|
+
return messages.find((m) => m.tool_call_id === id);
|
|
132
|
+
};
|
|
128
133
|
const getTraceIdByMessageId = (id: string) => (s: ChatStore) => getMessageById(id)(s)?.traceId;
|
|
129
134
|
|
|
130
135
|
const latestMessage = (s: ChatStore) => currentChats(s).at(-1);
|
|
@@ -160,6 +165,7 @@ export const chatSelectors = {
|
|
|
160
165
|
currentChatsWithHistoryConfig,
|
|
161
166
|
currentToolMessages,
|
|
162
167
|
getMessageById,
|
|
168
|
+
getMessageByToolCallId,
|
|
163
169
|
getTraceIdByMessageId,
|
|
164
170
|
isAIGenerating,
|
|
165
171
|
isCreatingMessage,
|
|
File without changes
|