@lobehub/chat 1.56.2 → 1.56.4
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/changelog/v1.json +18 -0
- package/package.json +1 -1
- package/src/app/[variants]/(main)/chat/(workspace)/features/AgentSettings/CategoryContent/useCategory.tsx +2 -2
- package/src/app/[variants]/(main)/chat/(workspace)/features/AgentSettings/index.tsx +1 -1
- package/src/database/server/models/aiProvider.ts +1 -0
- package/src/features/AgentSetting/AgentMeta/index.tsx +4 -1
- package/src/server/routers/lambda/agent.test.ts +306 -0
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,56 @@
|
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
5
|
+
### [Version 1.56.4](https://github.com/lobehub/lobe-chat/compare/v1.56.3...v1.56.4)
|
6
|
+
|
7
|
+
<sup>Released on **2025-02-16**</sup>
|
8
|
+
|
9
|
+
#### 🐛 Bug Fixes
|
10
|
+
|
11
|
+
- **misc**: Fix ai provider description not show correctly.
|
12
|
+
|
13
|
+
<br/>
|
14
|
+
|
15
|
+
<details>
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
17
|
+
|
18
|
+
#### What's fixed
|
19
|
+
|
20
|
+
- **misc**: Fix ai provider description not show correctly, closes [#6199](https://github.com/lobehub/lobe-chat/issues/6199) ([3e8d9c5](https://github.com/lobehub/lobe-chat/commit/3e8d9c5))
|
21
|
+
|
22
|
+
</details>
|
23
|
+
|
24
|
+
<div align="right">
|
25
|
+
|
26
|
+
[](#readme-top)
|
27
|
+
|
28
|
+
</div>
|
29
|
+
|
30
|
+
### [Version 1.56.3](https://github.com/lobehub/lobe-chat/compare/v1.56.2...v1.56.3)
|
31
|
+
|
32
|
+
<sup>Released on **2025-02-16**</sup>
|
33
|
+
|
34
|
+
#### 💄 Styles
|
35
|
+
|
36
|
+
- **misc**: Improve inbox agent settings.
|
37
|
+
|
38
|
+
<br/>
|
39
|
+
|
40
|
+
<details>
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
42
|
+
|
43
|
+
#### Styles
|
44
|
+
|
45
|
+
- **misc**: Improve inbox agent settings, closes [#6197](https://github.com/lobehub/lobe-chat/issues/6197) ([37b70f0](https://github.com/lobehub/lobe-chat/commit/37b70f0))
|
46
|
+
|
47
|
+
</details>
|
48
|
+
|
49
|
+
<div align="right">
|
50
|
+
|
51
|
+
[](#readme-top)
|
52
|
+
|
53
|
+
</div>
|
54
|
+
|
5
55
|
### [Version 1.56.2](https://github.com/lobehub/lobe-chat/compare/v1.56.1...v1.56.2)
|
6
56
|
|
7
57
|
<sup>Released on **2025-02-16**</sup>
|
package/changelog/v1.json
CHANGED
@@ -1,4 +1,22 @@
|
|
1
1
|
[
|
2
|
+
{
|
3
|
+
"children": {
|
4
|
+
"fixes": [
|
5
|
+
"Fix ai provider description not show correctly."
|
6
|
+
]
|
7
|
+
},
|
8
|
+
"date": "2025-02-16",
|
9
|
+
"version": "1.56.4"
|
10
|
+
},
|
11
|
+
{
|
12
|
+
"children": {
|
13
|
+
"improvements": [
|
14
|
+
"Improve inbox agent settings."
|
15
|
+
]
|
16
|
+
},
|
17
|
+
"date": "2025-02-16",
|
18
|
+
"version": "1.56.3"
|
19
|
+
},
|
2
20
|
{
|
3
21
|
"children": {
|
4
22
|
"fixes": [
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@lobehub/chat",
|
3
|
-
"version": "1.56.
|
3
|
+
"version": "1.56.4",
|
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",
|
@@ -27,11 +27,11 @@ export const useCategory = ({ mobile }: UseCategoryOptions = {}) => {
|
|
27
27
|
key: ChatSettingsTabs.Meta,
|
28
28
|
label: t('agentTab.meta'),
|
29
29
|
}) as MenuItemType,
|
30
|
-
|
30
|
+
{
|
31
31
|
icon: <Icon icon={Bot} size={iconSize} />,
|
32
32
|
key: ChatSettingsTabs.Prompt,
|
33
33
|
label: t('agentTab.prompt'),
|
34
|
-
}
|
34
|
+
},
|
35
35
|
{
|
36
36
|
icon: <Icon icon={MessagesSquare} size={iconSize} />,
|
37
37
|
key: ChatSettingsTabs.Chat,
|
@@ -41,7 +41,7 @@ const AgentSettings = memo(() => {
|
|
41
41
|
]);
|
42
42
|
const isInbox = id === INBOX_SESSION_ID;
|
43
43
|
|
44
|
-
const [tab, setTab] = useState(isInbox ? ChatSettingsTabs.
|
44
|
+
const [tab, setTab] = useState(isInbox ? ChatSettingsTabs.Prompt : ChatSettingsTabs.Meta);
|
45
45
|
|
46
46
|
const ref = useRef<any>(null);
|
47
47
|
const theme = useTheme();
|
@@ -170,6 +170,7 @@ export class AiProviderModel {
|
|
170
170
|
const query = this.db
|
171
171
|
.select({
|
172
172
|
checkModel: aiProviders.checkModel,
|
173
|
+
description: aiProviders.description,
|
173
174
|
enabled: aiProviders.enabled,
|
174
175
|
fetchOnClient: aiProviders.fetchOnClient,
|
175
176
|
id: aiProviders.id,
|
@@ -9,6 +9,7 @@ import { memo } from 'react';
|
|
9
9
|
import { useTranslation } from 'react-i18next';
|
10
10
|
|
11
11
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
12
|
+
import { INBOX_SESSION_ID } from '@/const/session';
|
12
13
|
|
13
14
|
import { useStore } from '../store';
|
14
15
|
import { SessionLoadingState } from '../store/initialState';
|
@@ -26,9 +27,11 @@ const AgentMeta = memo(() => {
|
|
26
27
|
s.autocompleteMeta,
|
27
28
|
s.autocompleteAllMeta,
|
28
29
|
]);
|
29
|
-
const loading = useStore((s) => s.autocompleteLoading);
|
30
|
+
const [isInbox, loading] = useStore((s) => [s.id === INBOX_SESSION_ID, s.autocompleteLoading]);
|
30
31
|
const meta = useStore((s) => s.meta, isEqual);
|
31
32
|
|
33
|
+
if (isInbox) return;
|
34
|
+
|
32
35
|
const basic = [
|
33
36
|
{
|
34
37
|
Render: AutoGenerateInput,
|
@@ -0,0 +1,306 @@
|
|
1
|
+
// @vitest-environment node
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
3
|
+
|
4
|
+
import { INBOX_SESSION_ID } from '@/const/session';
|
5
|
+
import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
|
6
|
+
import { serverDB } from '@/database/server';
|
7
|
+
import { AgentModel } from '@/database/server/models/agent';
|
8
|
+
import { FileModel } from '@/database/server/models/file';
|
9
|
+
import { KnowledgeBaseModel } from '@/database/server/models/knowledgeBase';
|
10
|
+
import { SessionModel } from '@/database/server/models/session';
|
11
|
+
import { UserModel } from '@/database/server/models/user';
|
12
|
+
import { AgentService } from '@/server/services/agent';
|
13
|
+
import { KnowledgeType } from '@/types/knowledgeBase';
|
14
|
+
|
15
|
+
import { agentRouter } from './agent';
|
16
|
+
|
17
|
+
vi.mock('@/database/server/models/user', () => ({
|
18
|
+
UserModel: {
|
19
|
+
findById: vi.fn(),
|
20
|
+
},
|
21
|
+
}));
|
22
|
+
|
23
|
+
vi.mock('@/database/server/models/agent', () => ({
|
24
|
+
AgentModel: vi.fn(),
|
25
|
+
}));
|
26
|
+
|
27
|
+
vi.mock('@/database/server/models/session', () => ({
|
28
|
+
SessionModel: vi.fn(),
|
29
|
+
}));
|
30
|
+
|
31
|
+
vi.mock('@/database/server/models/file', () => ({
|
32
|
+
FileModel: vi.fn(),
|
33
|
+
}));
|
34
|
+
|
35
|
+
vi.mock('@/database/server/models/knowledgeBase', () => ({
|
36
|
+
KnowledgeBaseModel: vi.fn(),
|
37
|
+
}));
|
38
|
+
|
39
|
+
vi.mock('@/server/services/agent', () => ({
|
40
|
+
AgentService: vi.fn(),
|
41
|
+
}));
|
42
|
+
|
43
|
+
describe('agentRouter', () => {
|
44
|
+
const userId = 'testUserId';
|
45
|
+
let mockCtx: any;
|
46
|
+
let agentModelMock: any;
|
47
|
+
let sessionModelMock: any;
|
48
|
+
let fileModelMock: any;
|
49
|
+
let knowledgeBaseModelMock: any;
|
50
|
+
let agentServiceMock: any;
|
51
|
+
|
52
|
+
beforeEach(() => {
|
53
|
+
vi.clearAllMocks();
|
54
|
+
|
55
|
+
agentModelMock = {
|
56
|
+
createAgentFiles: vi.fn(),
|
57
|
+
createAgentKnowledgeBase: vi.fn(),
|
58
|
+
deleteAgentFile: vi.fn(),
|
59
|
+
deleteAgentKnowledgeBase: vi.fn(),
|
60
|
+
findBySessionId: vi.fn(),
|
61
|
+
getAgentAssignedKnowledge: vi.fn(),
|
62
|
+
toggleFile: vi.fn(),
|
63
|
+
toggleKnowledgeBase: vi.fn(),
|
64
|
+
};
|
65
|
+
vi.mocked(AgentModel).mockImplementation(() => agentModelMock);
|
66
|
+
|
67
|
+
sessionModelMock = {
|
68
|
+
findByIdOrSlug: vi.fn(),
|
69
|
+
};
|
70
|
+
vi.mocked(SessionModel).mockImplementation(() => sessionModelMock);
|
71
|
+
|
72
|
+
fileModelMock = {
|
73
|
+
query: vi.fn(),
|
74
|
+
};
|
75
|
+
vi.mocked(FileModel).mockImplementation(() => fileModelMock);
|
76
|
+
|
77
|
+
knowledgeBaseModelMock = {
|
78
|
+
query: vi.fn(),
|
79
|
+
};
|
80
|
+
vi.mocked(KnowledgeBaseModel).mockImplementation(() => knowledgeBaseModelMock);
|
81
|
+
|
82
|
+
agentServiceMock = {
|
83
|
+
createInbox: vi.fn(),
|
84
|
+
};
|
85
|
+
vi.mocked(AgentService).mockImplementation(() => agentServiceMock);
|
86
|
+
|
87
|
+
mockCtx = {
|
88
|
+
userId,
|
89
|
+
agentModel: agentModelMock,
|
90
|
+
agentService: agentServiceMock,
|
91
|
+
fileModel: fileModelMock,
|
92
|
+
knowledgeBaseModel: knowledgeBaseModelMock,
|
93
|
+
sessionModel: sessionModelMock,
|
94
|
+
};
|
95
|
+
});
|
96
|
+
|
97
|
+
describe('getAgentConfig', () => {
|
98
|
+
it('should return default config if user not found when getting inbox config', async () => {
|
99
|
+
vi.mocked(UserModel.findById).mockResolvedValue(undefined);
|
100
|
+
sessionModelMock.findByIdOrSlug.mockResolvedValue(undefined);
|
101
|
+
|
102
|
+
const caller = agentRouter.createCaller(mockCtx);
|
103
|
+
const result = await caller.getAgentConfig({ sessionId: INBOX_SESSION_ID });
|
104
|
+
|
105
|
+
expect(result).toEqual(DEFAULT_AGENT_CONFIG);
|
106
|
+
});
|
107
|
+
|
108
|
+
it('should create inbox session if user exists but no inbox session', async () => {
|
109
|
+
const mockUser = { id: userId };
|
110
|
+
const mockSession = { id: 'inboxSessionId' };
|
111
|
+
|
112
|
+
vi.mocked(UserModel.findById).mockResolvedValue(mockUser as any);
|
113
|
+
sessionModelMock.findByIdOrSlug
|
114
|
+
.mockResolvedValueOnce(undefined)
|
115
|
+
.mockResolvedValueOnce(mockSession);
|
116
|
+
agentModelMock.findBySessionId.mockResolvedValue(DEFAULT_AGENT_CONFIG);
|
117
|
+
|
118
|
+
const caller = agentRouter.createCaller(mockCtx);
|
119
|
+
const result = await caller.getAgentConfig({ sessionId: INBOX_SESSION_ID });
|
120
|
+
|
121
|
+
expect(agentServiceMock.createInbox).toHaveBeenCalled();
|
122
|
+
expect(result).toEqual(DEFAULT_AGENT_CONFIG);
|
123
|
+
});
|
124
|
+
|
125
|
+
it('should find agent by session id if session exists', async () => {
|
126
|
+
const mockSession = { id: 'session1' };
|
127
|
+
sessionModelMock.findByIdOrSlug.mockResolvedValue(mockSession);
|
128
|
+
agentModelMock.findBySessionId.mockResolvedValue(DEFAULT_AGENT_CONFIG);
|
129
|
+
|
130
|
+
const caller = agentRouter.createCaller(mockCtx);
|
131
|
+
const result = await caller.getAgentConfig({ sessionId: 'session1' });
|
132
|
+
|
133
|
+
expect(agentModelMock.findBySessionId).toHaveBeenCalledWith('session1');
|
134
|
+
expect(result).toEqual(DEFAULT_AGENT_CONFIG);
|
135
|
+
});
|
136
|
+
});
|
137
|
+
|
138
|
+
describe('getKnowledgeBasesAndFiles', () => {
|
139
|
+
it('should return combined knowledge bases and files', async () => {
|
140
|
+
const mockFiles = [
|
141
|
+
{ id: 'file1', name: 'File 1', fileType: 'text' },
|
142
|
+
{ id: 'file2', name: 'File 2', fileType: 'pdf' },
|
143
|
+
];
|
144
|
+
|
145
|
+
const mockKnowledgeBases = [
|
146
|
+
{ id: 'kb1', name: 'KB 1', description: 'desc 1', avatar: 'avatar1' },
|
147
|
+
{ id: 'kb2', name: 'KB 2', description: 'desc 2', avatar: 'avatar2' },
|
148
|
+
];
|
149
|
+
|
150
|
+
const mockKnowledge = {
|
151
|
+
files: [{ id: 'file1', enabled: true }],
|
152
|
+
knowledgeBases: [{ id: 'kb1', enabled: true }],
|
153
|
+
};
|
154
|
+
|
155
|
+
fileModelMock.query.mockResolvedValue(mockFiles);
|
156
|
+
knowledgeBaseModelMock.query.mockResolvedValue(mockKnowledgeBases);
|
157
|
+
agentModelMock.getAgentAssignedKnowledge.mockResolvedValue(mockKnowledge);
|
158
|
+
|
159
|
+
const caller = agentRouter.createCaller(mockCtx);
|
160
|
+
const result = await caller.getKnowledgeBasesAndFiles({ agentId: 'agent1' });
|
161
|
+
|
162
|
+
expect(result).toEqual([
|
163
|
+
{
|
164
|
+
enabled: true,
|
165
|
+
fileType: 'text',
|
166
|
+
id: 'file1',
|
167
|
+
name: 'File 1',
|
168
|
+
type: KnowledgeType.File,
|
169
|
+
},
|
170
|
+
{
|
171
|
+
enabled: false,
|
172
|
+
fileType: 'pdf',
|
173
|
+
id: 'file2',
|
174
|
+
name: 'File 2',
|
175
|
+
type: KnowledgeType.File,
|
176
|
+
},
|
177
|
+
{
|
178
|
+
avatar: 'avatar1',
|
179
|
+
description: 'desc 1',
|
180
|
+
enabled: true,
|
181
|
+
id: 'kb1',
|
182
|
+
name: 'KB 1',
|
183
|
+
type: KnowledgeType.KnowledgeBase,
|
184
|
+
},
|
185
|
+
{
|
186
|
+
avatar: 'avatar2',
|
187
|
+
description: 'desc 2',
|
188
|
+
enabled: false,
|
189
|
+
id: 'kb2',
|
190
|
+
name: 'KB 2',
|
191
|
+
type: KnowledgeType.KnowledgeBase,
|
192
|
+
},
|
193
|
+
]);
|
194
|
+
});
|
195
|
+
});
|
196
|
+
|
197
|
+
describe('createAgentFiles', () => {
|
198
|
+
it('should create agent files', async () => {
|
199
|
+
const mockInput = {
|
200
|
+
agentId: 'agent1',
|
201
|
+
fileIds: ['file1', 'file2'],
|
202
|
+
enabled: true,
|
203
|
+
};
|
204
|
+
|
205
|
+
const caller = agentRouter.createCaller(mockCtx);
|
206
|
+
await caller.createAgentFiles(mockInput);
|
207
|
+
|
208
|
+
expect(agentModelMock.createAgentFiles).toHaveBeenCalledWith(
|
209
|
+
mockInput.agentId,
|
210
|
+
mockInput.fileIds,
|
211
|
+
mockInput.enabled,
|
212
|
+
);
|
213
|
+
});
|
214
|
+
});
|
215
|
+
|
216
|
+
describe('deleteAgentFile', () => {
|
217
|
+
it('should delete agent file', async () => {
|
218
|
+
const mockInput = {
|
219
|
+
agentId: 'agent1',
|
220
|
+
fileId: 'file1',
|
221
|
+
};
|
222
|
+
|
223
|
+
const caller = agentRouter.createCaller(mockCtx);
|
224
|
+
await caller.deleteAgentFile(mockInput);
|
225
|
+
|
226
|
+
expect(agentModelMock.deleteAgentFile).toHaveBeenCalledWith(
|
227
|
+
mockInput.agentId,
|
228
|
+
mockInput.fileId,
|
229
|
+
);
|
230
|
+
});
|
231
|
+
});
|
232
|
+
|
233
|
+
describe('toggleFile', () => {
|
234
|
+
it('should toggle file', async () => {
|
235
|
+
const mockInput = {
|
236
|
+
agentId: 'agent1',
|
237
|
+
fileId: 'file1',
|
238
|
+
enabled: true,
|
239
|
+
};
|
240
|
+
|
241
|
+
const caller = agentRouter.createCaller(mockCtx);
|
242
|
+
await caller.toggleFile(mockInput);
|
243
|
+
|
244
|
+
expect(agentModelMock.toggleFile).toHaveBeenCalledWith(
|
245
|
+
mockInput.agentId,
|
246
|
+
mockInput.fileId,
|
247
|
+
mockInput.enabled,
|
248
|
+
);
|
249
|
+
});
|
250
|
+
});
|
251
|
+
|
252
|
+
describe('createAgentKnowledgeBase', () => {
|
253
|
+
it('should create agent knowledge base', async () => {
|
254
|
+
const mockInput = {
|
255
|
+
agentId: 'agent1',
|
256
|
+
knowledgeBaseId: 'kb1',
|
257
|
+
enabled: true,
|
258
|
+
};
|
259
|
+
|
260
|
+
const caller = agentRouter.createCaller(mockCtx);
|
261
|
+
await caller.createAgentKnowledgeBase(mockInput);
|
262
|
+
|
263
|
+
expect(agentModelMock.createAgentKnowledgeBase).toHaveBeenCalledWith(
|
264
|
+
mockInput.agentId,
|
265
|
+
mockInput.knowledgeBaseId,
|
266
|
+
mockInput.enabled,
|
267
|
+
);
|
268
|
+
});
|
269
|
+
});
|
270
|
+
|
271
|
+
describe('deleteAgentKnowledgeBase', () => {
|
272
|
+
it('should delete agent knowledge base', async () => {
|
273
|
+
const mockInput = {
|
274
|
+
agentId: 'agent1',
|
275
|
+
knowledgeBaseId: 'kb1',
|
276
|
+
};
|
277
|
+
|
278
|
+
const caller = agentRouter.createCaller(mockCtx);
|
279
|
+
await caller.deleteAgentKnowledgeBase(mockInput);
|
280
|
+
|
281
|
+
expect(agentModelMock.deleteAgentKnowledgeBase).toHaveBeenCalledWith(
|
282
|
+
mockInput.agentId,
|
283
|
+
mockInput.knowledgeBaseId,
|
284
|
+
);
|
285
|
+
});
|
286
|
+
});
|
287
|
+
|
288
|
+
describe('toggleKnowledgeBase', () => {
|
289
|
+
it('should toggle knowledge base', async () => {
|
290
|
+
const mockInput = {
|
291
|
+
agentId: 'agent1',
|
292
|
+
knowledgeBaseId: 'kb1',
|
293
|
+
enabled: true,
|
294
|
+
};
|
295
|
+
|
296
|
+
const caller = agentRouter.createCaller(mockCtx);
|
297
|
+
await caller.toggleKnowledgeBase(mockInput);
|
298
|
+
|
299
|
+
expect(agentModelMock.toggleKnowledgeBase).toHaveBeenCalledWith(
|
300
|
+
mockInput.agentId,
|
301
|
+
mockInput.knowledgeBaseId,
|
302
|
+
mockInput.enabled,
|
303
|
+
);
|
304
|
+
});
|
305
|
+
});
|
306
|
+
});
|