@lobehub/chat 1.2.6 → 1.2.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/package.json +2 -2
- package/src/app/(main)/chat/(workspace)/@portal/features/ArtifactUI/Footer.tsx +1 -1
- package/src/app/(main)/chat/(workspace)/@portal/features/Header.tsx +1 -1
- package/src/app/(main)/chat/(workspace)/_layout/Mobile/PortalModal.tsx +35 -0
- package/src/app/(main)/chat/(workspace)/_layout/Mobile/index.tsx +3 -1
- package/src/database/client/models/__tests__/message.test.ts +13 -0
- package/src/database/client/models/message.ts +4 -0
- package/src/database/server/models/__tests__/message.test.ts +103 -0
- package/src/database/server/models/message.ts +13 -6
- package/src/features/Conversation/Actions/Tool.tsx +12 -6
- package/src/features/Conversation/Messages/Tool/Inspector/index.tsx +25 -19
- package/src/features/Conversation/Messages/Tool/Inspector/style.ts +9 -0
- package/src/server/routers/lambda/message.ts +7 -1
- package/src/services/message/client.test.ts +16 -2
- package/src/services/message/client.ts +5 -1
- package/src/services/message/server.ts +7 -2
- package/src/services/message/type.ts +2 -1
- package/src/store/chat/slices/message/action.test.ts +144 -0
- package/src/store/chat/slices/message/action.ts +111 -64
- package/src/store/chat/slices/message/reducer.test.ts +200 -1
- package/src/store/chat/slices/message/reducer.ts +62 -2
- package/src/store/chat/slices/plugin/action.test.ts +42 -0
- package/src/store/chat/slices/plugin/action.ts +48 -2
- package/src/store/chat/slices/portal/action.test.ts +6 -6
- package/src/store/chat/slices/portal/action.ts +3 -3
- package/src/store/chat/slices/topic/action.test.ts +3 -2
- package/src/store/chat/slices/topic/action.ts +1 -1
- package/src/store/global/action.test.ts +13 -0
- package/src/store/global/action.ts +7 -0
- package/src/store/global/initialState.ts +1 -0
- package/src/store/global/selectors.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 1.2.8](https://github.com/lobehub/lobe-chat/compare/v1.2.7...v1.2.8)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-07-03**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: Allow builtin tools to trigger AI message.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: Allow builtin tools to trigger AI message, closes [#3135](https://github.com/lobehub/lobe-chat/issues/3135) ([6c4c8f7](https://github.com/lobehub/lobe-chat/commit/6c4c8f7))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 1.2.7](https://github.com/lobehub/lobe-chat/compare/v1.2.6...v1.2.7)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2024-07-03**</sup>
|
|
33
|
+
|
|
34
|
+
#### 💄 Styles
|
|
35
|
+
|
|
36
|
+
- **misc**: Improve delete assistant message with tools.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Styles
|
|
44
|
+
|
|
45
|
+
- **misc**: Improve delete assistant message with tools, closes [#3127](https://github.com/lobehub/lobe-chat/issues/3127) ([1230777](https://github.com/lobehub/lobe-chat/commit/1230777))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 1.2.6](https://github.com/lobehub/lobe-chat/compare/v1.2.5...v1.2.6)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2024-07-03**</sup>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.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",
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
"@azure/openai": "1.0.0-beta.12",
|
|
107
107
|
"@cfworker/json-schema": "^1.12.8",
|
|
108
108
|
"@clerk/localizations": "2.0.0",
|
|
109
|
-
"@clerk/nextjs": "
|
|
109
|
+
"@clerk/nextjs": "5.1.6",
|
|
110
110
|
"@clerk/themes": "^2.1.10",
|
|
111
111
|
"@google/generative-ai": "^0.13.0",
|
|
112
112
|
"@icons-pack/react-simple-icons": "^9.5.0",
|
|
@@ -18,7 +18,7 @@ import { toolSelectors } from '@/store/tool/selectors';
|
|
|
18
18
|
const Header = memo(() => {
|
|
19
19
|
const [showToolUI, toggleInspector, closeToolUI, toolUIIdentifier = ''] = useChatStore((s) => [
|
|
20
20
|
chatPortalSelectors.showArtifactUI(s),
|
|
21
|
-
s.
|
|
21
|
+
s.togglePortal,
|
|
22
22
|
s.closeToolUI,
|
|
23
23
|
chatPortalSelectors.toolUIIdentifier(s),
|
|
24
24
|
]);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Modal } from '@lobehub/ui';
|
|
4
|
+
import { PropsWithChildren, memo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
|
|
7
|
+
import { useGlobalStore } from '@/store/global';
|
|
8
|
+
import { systemStatusSelectors } from '@/store/global/selectors';
|
|
9
|
+
|
|
10
|
+
import { useWorkspaceModal } from '../../features/useWorkspaceModal';
|
|
11
|
+
|
|
12
|
+
const PortalModal = memo(({ children }: PropsWithChildren) => {
|
|
13
|
+
const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
|
|
14
|
+
systemStatusSelectors.mobileShowPortal(s),
|
|
15
|
+
s.toggleMobilePortal,
|
|
16
|
+
]);
|
|
17
|
+
const [open, setOpen] = useWorkspaceModal(showAgentSettings, toggleConfig);
|
|
18
|
+
const { t } = useTranslation('portal');
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Modal
|
|
22
|
+
height={'95%'}
|
|
23
|
+
onCancel={() => setOpen(false)}
|
|
24
|
+
open={open}
|
|
25
|
+
styles={{
|
|
26
|
+
body: { padding: 0 },
|
|
27
|
+
}}
|
|
28
|
+
title={t('title')}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
</Modal>
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export default PortalModal;
|
|
@@ -2,9 +2,10 @@ import MobileContentLayout from '@/components/server/MobileNavLayout';
|
|
|
2
2
|
|
|
3
3
|
import { LayoutProps } from '../type';
|
|
4
4
|
import ChatHeader from './ChatHeader';
|
|
5
|
+
import PortalModal from './PortalModal';
|
|
5
6
|
import TopicModal from './TopicModal';
|
|
6
7
|
|
|
7
|
-
const Layout = ({ children, topic, conversation }: LayoutProps) => {
|
|
8
|
+
const Layout = ({ children, topic, conversation, portal }: LayoutProps) => {
|
|
8
9
|
return (
|
|
9
10
|
<>
|
|
10
11
|
<MobileContentLayout header={<ChatHeader />} style={{ overflowY: 'hidden' }}>
|
|
@@ -12,6 +13,7 @@ const Layout = ({ children, topic, conversation }: LayoutProps) => {
|
|
|
12
13
|
{children}
|
|
13
14
|
</MobileContentLayout>
|
|
14
15
|
<TopicModal>{topic}</TopicModal>
|
|
16
|
+
<PortalModal>{portal}</PortalModal>
|
|
15
17
|
</>
|
|
16
18
|
);
|
|
17
19
|
};
|
|
@@ -250,6 +250,19 @@ describe('MessageModel', () => {
|
|
|
250
250
|
});
|
|
251
251
|
});
|
|
252
252
|
|
|
253
|
+
describe('bulkDelete', () => {
|
|
254
|
+
it('should delete many messages', async () => {
|
|
255
|
+
const createdMessage = await MessageModel.create(messageData);
|
|
256
|
+
const createdMessage2 = await MessageModel.create(messageData);
|
|
257
|
+
await MessageModel.bulkDelete([createdMessage.id, createdMessage2.id]);
|
|
258
|
+
|
|
259
|
+
const messageInDb1 = await MessageModel.findById(createdMessage.id);
|
|
260
|
+
const messageInDb2 = await MessageModel.findById(createdMessage2.id);
|
|
261
|
+
expect(messageInDb1).toBeUndefined();
|
|
262
|
+
expect(messageInDb2).toBeUndefined();
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
253
266
|
describe('update', () => {
|
|
254
267
|
it('should update a message', async () => {
|
|
255
268
|
const createdMessage = await MessageModel.create(messageData);
|
|
@@ -491,6 +491,75 @@ describe('MessageModel', () => {
|
|
|
491
491
|
expect(pluginResult).toHaveLength(1);
|
|
492
492
|
expect(pluginResult[0].identifier).toBe('plugin1');
|
|
493
493
|
});
|
|
494
|
+
|
|
495
|
+
it('should create tool message ', async () => {
|
|
496
|
+
// 调用 create 方法
|
|
497
|
+
const state = {
|
|
498
|
+
query: 'Composio',
|
|
499
|
+
answers: [],
|
|
500
|
+
results: [
|
|
501
|
+
{
|
|
502
|
+
url: 'https://www.composio.dev/',
|
|
503
|
+
score: 16,
|
|
504
|
+
title: 'Composio - Connect 90+ tools to your AI agents',
|
|
505
|
+
engine: 'bing',
|
|
506
|
+
content:
|
|
507
|
+
'Faster DevelopmentHigher ReliabilityBetter Integrations. Get Started Now. Our platform lets you ditch the specs and seamlessly integrate any tool you need in less than 5 mins.',
|
|
508
|
+
engines: ['bing', 'qwant', 'brave', 'duckduckgo'],
|
|
509
|
+
category: 'general',
|
|
510
|
+
template: 'default.html',
|
|
511
|
+
positions: [1, 1, 1, 1],
|
|
512
|
+
thumbnail: '',
|
|
513
|
+
parsed_url: ['https', 'www.composio.dev', '/', '', '', ''],
|
|
514
|
+
publishedDate: null,
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
url: 'https://www.composio.co/',
|
|
518
|
+
score: 10.75,
|
|
519
|
+
title: 'Composio',
|
|
520
|
+
engine: 'bing',
|
|
521
|
+
content:
|
|
522
|
+
'Composio was created to help streamline the entire book creation process! Writing. Take time out to write / Make a schedule to write consistently. We have writing software that optimizes your books for printing or ebook format. Figure out what you want to write. Collaborate and write with others. Professional editing is a necessity.',
|
|
523
|
+
engines: ['qwant', 'duckduckgo', 'google', 'bing', 'brave'],
|
|
524
|
+
category: 'general',
|
|
525
|
+
template: 'default.html',
|
|
526
|
+
positions: [5, 2, 1, 5, 4],
|
|
527
|
+
thumbnail: null,
|
|
528
|
+
parsed_url: ['https', 'www.composio.co', '/', '', '', ''],
|
|
529
|
+
publishedDate: null,
|
|
530
|
+
},
|
|
531
|
+
],
|
|
532
|
+
unresponsive_engines: [],
|
|
533
|
+
};
|
|
534
|
+
const result = await messageModel.create({
|
|
535
|
+
content: '[{}]',
|
|
536
|
+
plugin: {
|
|
537
|
+
apiName: 'searchWithSearXNG',
|
|
538
|
+
arguments: '{\n "query": "Composio"\n}',
|
|
539
|
+
identifier: 'lobe-web-browsing',
|
|
540
|
+
type: 'builtin',
|
|
541
|
+
},
|
|
542
|
+
pluginState: state,
|
|
543
|
+
role: 'tool',
|
|
544
|
+
tool_call_id: 'tool_call_ymxXC2J0',
|
|
545
|
+
sessionId: '1',
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
// 断言结果
|
|
549
|
+
expect(result.id).toBeDefined();
|
|
550
|
+
expect(result.content).toBe('[{}]');
|
|
551
|
+
expect(result.role).toBe('tool');
|
|
552
|
+
expect(result.sessionId).toBe('1');
|
|
553
|
+
|
|
554
|
+
const pluginResult = await serverDB
|
|
555
|
+
.select()
|
|
556
|
+
.from(messagePlugins)
|
|
557
|
+
.where(eq(messagePlugins.id, result.id))
|
|
558
|
+
.execute();
|
|
559
|
+
expect(pluginResult).toHaveLength(1);
|
|
560
|
+
expect(pluginResult[0].identifier).toBe('lobe-web-browsing');
|
|
561
|
+
expect(pluginResult[0].state!).toMatchObject(state);
|
|
562
|
+
});
|
|
494
563
|
});
|
|
495
564
|
|
|
496
565
|
describe('batchCreateMessages', () => {
|
|
@@ -645,6 +714,40 @@ describe('MessageModel', () => {
|
|
|
645
714
|
});
|
|
646
715
|
});
|
|
647
716
|
|
|
717
|
+
describe('deleteMessages', () => {
|
|
718
|
+
it('should delete 2 messages', async () => {
|
|
719
|
+
// 创建测试数据
|
|
720
|
+
await serverDB.insert(messages).values([
|
|
721
|
+
{ id: '1', userId, role: 'user', content: 'message 1' },
|
|
722
|
+
{ id: '2', userId, role: 'user', content: 'message 2' },
|
|
723
|
+
]);
|
|
724
|
+
|
|
725
|
+
// 调用 deleteMessage 方法
|
|
726
|
+
await messageModel.deleteMessages(['1', '2']);
|
|
727
|
+
|
|
728
|
+
// 断言结果
|
|
729
|
+
const result = await serverDB.select().from(messages).where(eq(messages.id, '1')).execute();
|
|
730
|
+
expect(result).toHaveLength(0);
|
|
731
|
+
const result2 = await serverDB.select().from(messages).where(eq(messages.id, '2')).execute();
|
|
732
|
+
expect(result2).toHaveLength(0);
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
it('should only delete messages belonging to the user', async () => {
|
|
736
|
+
// 创建测试数据
|
|
737
|
+
await serverDB.insert(messages).values([
|
|
738
|
+
{ id: '1', userId: '456', role: 'user', content: 'message 1' },
|
|
739
|
+
{ id: '2', userId: '456', role: 'user', content: 'message 1' },
|
|
740
|
+
]);
|
|
741
|
+
|
|
742
|
+
// 调用 deleteMessage 方法
|
|
743
|
+
await messageModel.deleteMessages(['1', '2']);
|
|
744
|
+
|
|
745
|
+
// 断言结果
|
|
746
|
+
const result = await serverDB.select().from(messages).where(eq(messages.id, '1')).execute();
|
|
747
|
+
expect(result).toHaveLength(1);
|
|
748
|
+
});
|
|
749
|
+
});
|
|
750
|
+
|
|
648
751
|
describe('deleteAllMessages', () => {
|
|
649
752
|
it('should delete all messages belonging to the user', async () => {
|
|
650
753
|
// 创建测试数据
|
|
@@ -206,7 +206,7 @@ export class MessageModel {
|
|
|
206
206
|
// **************** Create *************** //
|
|
207
207
|
|
|
208
208
|
async create(
|
|
209
|
-
{ fromModel, fromProvider, files, ...message }: CreateMessageParams,
|
|
209
|
+
{ fromModel, fromProvider, files, plugin, pluginState, ...message }: CreateMessageParams,
|
|
210
210
|
id: string = this.genId(),
|
|
211
211
|
): Promise<MessageItem> {
|
|
212
212
|
return serverDB.transaction(async (trx) => {
|
|
@@ -224,12 +224,13 @@ export class MessageModel {
|
|
|
224
224
|
// Insert the plugin data if the message is a tool
|
|
225
225
|
if (message.role === 'tool') {
|
|
226
226
|
await trx.insert(messagePlugins).values({
|
|
227
|
-
apiName:
|
|
228
|
-
arguments:
|
|
227
|
+
apiName: plugin?.apiName,
|
|
228
|
+
arguments: plugin?.arguments,
|
|
229
229
|
id,
|
|
230
|
-
identifier:
|
|
230
|
+
identifier: plugin?.identifier,
|
|
231
|
+
state: pluginState,
|
|
231
232
|
toolCallId: message.tool_call_id,
|
|
232
|
-
type:
|
|
233
|
+
type: plugin?.type,
|
|
233
234
|
});
|
|
234
235
|
}
|
|
235
236
|
|
|
@@ -352,6 +353,12 @@ export class MessageModel {
|
|
|
352
353
|
});
|
|
353
354
|
}
|
|
354
355
|
|
|
356
|
+
async deleteMessages(ids: string[]) {
|
|
357
|
+
return serverDB
|
|
358
|
+
.delete(messages)
|
|
359
|
+
.where(and(eq(messages.userId, this.userId), inArray(messages.id, ids)));
|
|
360
|
+
}
|
|
361
|
+
|
|
355
362
|
async deleteMessageTranslate(id: string) {
|
|
356
363
|
return serverDB.delete(messageTranslates).where(and(eq(messageTranslates.id, id)));
|
|
357
364
|
}
|
|
@@ -360,7 +367,7 @@ export class MessageModel {
|
|
|
360
367
|
return serverDB.delete(messageTTS).where(and(eq(messageTTS.id, id)));
|
|
361
368
|
}
|
|
362
369
|
|
|
363
|
-
async
|
|
370
|
+
async deleteMessagesBySession(sessionId?: string | null, topicId?: string | null) {
|
|
364
371
|
return serverDB
|
|
365
372
|
.delete(messages)
|
|
366
373
|
.where(
|
|
@@ -7,19 +7,25 @@ import { useChatListActionsBar } from '../hooks/useChatListActionsBar';
|
|
|
7
7
|
import { RenderAction } from '../types';
|
|
8
8
|
|
|
9
9
|
export const ToolActionsBar: RenderAction = memo(({ id }) => {
|
|
10
|
-
const { regenerate } = useChatListActionsBar();
|
|
11
|
-
const [reInvokeToolMessage] = useChatStore((s) => [
|
|
10
|
+
const { regenerate, del } = useChatListActionsBar();
|
|
11
|
+
const [reInvokeToolMessage, deleteToolMessage] = useChatStore((s) => [
|
|
12
|
+
s.reInvokeToolMessage,
|
|
13
|
+
s.deleteToolMessage,
|
|
14
|
+
]);
|
|
12
15
|
|
|
13
16
|
return (
|
|
14
17
|
<ActionIconGroup
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
onActionClick={(event) => {
|
|
18
|
+
items={[regenerate, del]}
|
|
19
|
+
onActionClick={async (event) => {
|
|
18
20
|
switch (event.key) {
|
|
19
21
|
case 'regenerate': {
|
|
20
|
-
reInvokeToolMessage(id);
|
|
22
|
+
await reInvokeToolMessage(id);
|
|
21
23
|
break;
|
|
22
24
|
}
|
|
25
|
+
|
|
26
|
+
case 'del': {
|
|
27
|
+
await deleteToolMessage(id);
|
|
28
|
+
}
|
|
23
29
|
}
|
|
24
30
|
}}
|
|
25
31
|
type="ghost"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Loading3QuartersOutlined } from '@ant-design/icons';
|
|
2
|
-
import { ActionIcon,
|
|
3
|
-
import { Tabs } from 'antd';
|
|
2
|
+
import { ActionIcon, Highlighter, Icon, Tag } from '@lobehub/ui';
|
|
3
|
+
import { Tabs, Typography } from 'antd';
|
|
4
4
|
import isEqual from 'fast-deep-equal';
|
|
5
5
|
import {
|
|
6
6
|
InspectionPanel,
|
|
@@ -8,15 +8,16 @@ import {
|
|
|
8
8
|
LucideBugOff,
|
|
9
9
|
LucideChevronDown,
|
|
10
10
|
LucideChevronRight,
|
|
11
|
-
LucideToyBrick,
|
|
12
11
|
} from 'lucide-react';
|
|
13
12
|
import { memo, useState } from 'react';
|
|
14
13
|
import { useTranslation } from 'react-i18next';
|
|
15
14
|
import { Flexbox } from 'react-layout-kit';
|
|
16
15
|
|
|
17
16
|
import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens';
|
|
17
|
+
import PluginAvatar from '@/features/PluginAvatar';
|
|
18
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
18
19
|
import { useChatStore } from '@/store/chat';
|
|
19
|
-
import { chatPortalSelectors } from '@/store/chat/
|
|
20
|
+
import { chatPortalSelectors } from '@/store/chat/selectors';
|
|
20
21
|
import { pluginHelpers, useToolStore } from '@/store/tool';
|
|
21
22
|
import { toolSelectors } from '@/store/tool/selectors';
|
|
22
23
|
import { ChatPluginPayload } from '@/types/message';
|
|
@@ -50,25 +51,19 @@ const Inspector = memo<InspectorProps>(
|
|
|
50
51
|
const { t } = useTranslation(['plugin', 'portal']);
|
|
51
52
|
const { styles } = useStyles();
|
|
52
53
|
const [open, setOpen] = useState(false);
|
|
53
|
-
const [isMessageToolUIOpen, openToolUI,
|
|
54
|
+
const [isMessageToolUIOpen, openToolUI, togglePortal] = useChatStore((s) => [
|
|
54
55
|
chatPortalSelectors.isArtifactMessageUIOpen(id)(s),
|
|
55
56
|
s.openToolUI,
|
|
56
|
-
s.
|
|
57
|
+
s.togglePortal,
|
|
57
58
|
]);
|
|
58
59
|
|
|
60
|
+
const isMobile = useIsMobile();
|
|
59
61
|
const pluginMeta = useToolStore(toolSelectors.getMetaById(identifier), isEqual);
|
|
60
62
|
|
|
61
63
|
const showRightAction = useToolStore(toolSelectors.isToolHasUI(identifier));
|
|
62
|
-
const pluginAvatar = pluginHelpers.getPluginAvatar(pluginMeta);
|
|
63
64
|
|
|
64
65
|
const pluginTitle = pluginHelpers.getPluginTitle(pluginMeta) ?? t('unknownPlugin');
|
|
65
66
|
|
|
66
|
-
const avatar = pluginAvatar ? (
|
|
67
|
-
<Avatar alt={pluginTitle} avatar={pluginAvatar} size={32} />
|
|
68
|
-
) : (
|
|
69
|
-
<Icon icon={LucideToyBrick} />
|
|
70
|
-
);
|
|
71
|
-
|
|
72
67
|
let args, params;
|
|
73
68
|
try {
|
|
74
69
|
args = JSON.stringify(payload, null, 2);
|
|
@@ -84,7 +79,7 @@ const Inspector = memo<InspectorProps>(
|
|
|
84
79
|
<Flexbox
|
|
85
80
|
align={'center'}
|
|
86
81
|
className={styles.container}
|
|
87
|
-
gap={8}
|
|
82
|
+
gap={isMobile ? 16 : 8}
|
|
88
83
|
horizontal
|
|
89
84
|
onClick={() => {
|
|
90
85
|
setShow?.(!showRender);
|
|
@@ -96,22 +91,33 @@ const Inspector = memo<InspectorProps>(
|
|
|
96
91
|
<Loading3QuartersOutlined spin />
|
|
97
92
|
</div>
|
|
98
93
|
) : (
|
|
99
|
-
|
|
94
|
+
<PluginAvatar identifier={identifier} size={isMobile ? 36 : undefined} />
|
|
95
|
+
)}
|
|
96
|
+
{isMobile ? (
|
|
97
|
+
<Flexbox>
|
|
98
|
+
<div>{pluginTitle}</div>
|
|
99
|
+
<Typography.Text className={styles.apiName} type={'secondary'}>
|
|
100
|
+
{payload?.apiName}
|
|
101
|
+
</Typography.Text>
|
|
102
|
+
</Flexbox>
|
|
103
|
+
) : (
|
|
104
|
+
<>
|
|
105
|
+
<div>{pluginTitle}</div>
|
|
106
|
+
<Tag>{payload?.apiName}</Tag>
|
|
107
|
+
</>
|
|
100
108
|
)}
|
|
101
|
-
<div>{pluginTitle}</div>
|
|
102
|
-
<Tag>{payload?.apiName}</Tag>
|
|
103
109
|
</Flexbox>
|
|
104
110
|
{showRightAction && <Icon icon={showRender ? LucideChevronDown : LucideChevronRight} />}
|
|
105
111
|
</Flexbox>
|
|
106
112
|
|
|
107
113
|
<Flexbox horizontal>
|
|
108
|
-
{showRightAction && (
|
|
114
|
+
{!isMobile && showRightAction && (
|
|
109
115
|
<ActionIcon
|
|
110
116
|
icon={InspectionPanel}
|
|
111
117
|
onClick={() => {
|
|
112
118
|
if (!isMessageToolUIOpen) openToolUI(id, identifier);
|
|
113
119
|
else {
|
|
114
|
-
|
|
120
|
+
togglePortal(false);
|
|
115
121
|
}
|
|
116
122
|
}}
|
|
117
123
|
size={DESKTOP_HEADER_ICON_SIZE}
|
|
@@ -1,6 +1,15 @@
|
|
|
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
|
|
|
@@ -82,6 +82,12 @@ export const messageRouter = router({
|
|
|
82
82
|
}),
|
|
83
83
|
|
|
84
84
|
removeMessages: messageProcedure
|
|
85
|
+
.input(z.object({ ids: z.array(z.string()) }))
|
|
86
|
+
.mutation(async ({ input, ctx }) => {
|
|
87
|
+
return ctx.messageModel.deleteMessages(input.ids);
|
|
88
|
+
}),
|
|
89
|
+
|
|
90
|
+
removeMessagesByAssistant: messageProcedure
|
|
85
91
|
.input(
|
|
86
92
|
z.object({
|
|
87
93
|
sessionId: z.string().nullable().optional(),
|
|
@@ -89,7 +95,7 @@ export const messageRouter = router({
|
|
|
89
95
|
}),
|
|
90
96
|
)
|
|
91
97
|
.mutation(async ({ input, ctx }) => {
|
|
92
|
-
return ctx.messageModel.
|
|
98
|
+
return ctx.messageModel.deleteMessagesBySession(input.sessionId, input.topicId);
|
|
93
99
|
}),
|
|
94
100
|
|
|
95
101
|
searchMessages: messageProcedure
|
|
@@ -23,6 +23,7 @@ vi.mock('@/database/client/models/message', () => {
|
|
|
23
23
|
count: vi.fn(),
|
|
24
24
|
query: vi.fn(),
|
|
25
25
|
delete: vi.fn(),
|
|
26
|
+
bulkDelete: vi.fn(),
|
|
26
27
|
queryBySessionId: vi.fn(),
|
|
27
28
|
update: vi.fn(),
|
|
28
29
|
updatePlugin: vi.fn(),
|
|
@@ -100,6 +101,19 @@ describe('MessageClientService', () => {
|
|
|
100
101
|
expect(result).toBe(true);
|
|
101
102
|
});
|
|
102
103
|
});
|
|
104
|
+
describe('removeMessages', () => {
|
|
105
|
+
it('should remove a message by id', async () => {
|
|
106
|
+
// Setup
|
|
107
|
+
(MessageModel.bulkDelete as Mock).mockResolvedValue(true);
|
|
108
|
+
|
|
109
|
+
// Execute
|
|
110
|
+
const result = await messageService.removeMessages([mockMessageId]);
|
|
111
|
+
|
|
112
|
+
// Assert
|
|
113
|
+
expect(MessageModel.bulkDelete).toHaveBeenCalledWith([mockMessageId]);
|
|
114
|
+
expect(result).toBe(true);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
103
117
|
|
|
104
118
|
describe('getMessages', () => {
|
|
105
119
|
it('should retrieve messages by sessionId and topicId', async () => {
|
|
@@ -132,7 +146,7 @@ describe('MessageClientService', () => {
|
|
|
132
146
|
});
|
|
133
147
|
});
|
|
134
148
|
|
|
135
|
-
describe('
|
|
149
|
+
describe('removeMessagesByAssistant', () => {
|
|
136
150
|
it('should batch remove messages by assistantId and topicId', async () => {
|
|
137
151
|
// Setup
|
|
138
152
|
const assistantId = 'assistant-id';
|
|
@@ -140,7 +154,7 @@ describe('MessageClientService', () => {
|
|
|
140
154
|
(MessageModel.batchDelete as Mock).mockResolvedValue(true);
|
|
141
155
|
|
|
142
156
|
// Execute
|
|
143
|
-
const result = await messageService.
|
|
157
|
+
const result = await messageService.removeMessagesByAssistant(assistantId, topicId);
|
|
144
158
|
|
|
145
159
|
// Assert
|
|
146
160
|
expect(MessageModel.batchDelete).toHaveBeenCalledWith(assistantId, topicId);
|
|
@@ -74,7 +74,11 @@ export class ClientService implements IMessageService {
|
|
|
74
74
|
return MessageModel.delete(id);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
async removeMessages(
|
|
77
|
+
async removeMessages(ids: string[]) {
|
|
78
|
+
return MessageModel.bulkDelete(ids);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async removeMessagesByAssistant(assistantId: string, topicId?: string) {
|
|
78
82
|
return MessageModel.batchDelete(assistantId, topicId);
|
|
79
83
|
}
|
|
80
84
|
|
|
@@ -80,8 +80,13 @@ export class ServerService implements IMessageService {
|
|
|
80
80
|
removeMessage(id: string): Promise<any> {
|
|
81
81
|
return lambdaClient.message.removeMessage.mutate({ id });
|
|
82
82
|
}
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
|
|
84
|
+
removeMessages(ids: string[]): Promise<any> {
|
|
85
|
+
return lambdaClient.message.removeMessages.mutate({ ids });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
removeMessagesByAssistant(sessionId: string, topicId?: string | undefined): Promise<any> {
|
|
89
|
+
return lambdaClient.message.removeMessagesByAssistant.mutate({
|
|
85
90
|
sessionId: this.toDbSessionId(sessionId),
|
|
86
91
|
topicId,
|
|
87
92
|
});
|
|
@@ -39,7 +39,8 @@ export interface IMessageService {
|
|
|
39
39
|
bindMessagesToTopic(topicId: string, messageIds: string[]): Promise<any>;
|
|
40
40
|
|
|
41
41
|
removeMessage(id: string): Promise<any>;
|
|
42
|
-
removeMessages(
|
|
42
|
+
removeMessages(ids: string[]): Promise<any>;
|
|
43
|
+
removeMessagesByAssistant(assistantId: string, topicId?: string): Promise<any>;
|
|
43
44
|
removeAllMessages(): Promise<any>;
|
|
44
45
|
|
|
45
46
|
hasMessages(): Promise<boolean>;
|