@lobehub/lobehub 2.0.0-next.346 → 2.0.0-next.348
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 +61 -0
- package/changelog/v1.json +21 -0
- package/package.json +1 -1
- package/packages/builtin-tool-group-agent-builder/src/client/Inspector/BatchCreateAgents/index.tsx +1 -1
- package/packages/database/src/models/__tests__/topics/topic.create.test.ts +124 -1
- package/packages/database/src/models/topic.ts +82 -20
- package/src/app/[variants]/(main)/agent/profile/features/AgentSettings/Content.tsx +133 -0
- package/src/app/[variants]/(main)/agent/profile/features/AgentSettings/index.tsx +35 -0
- package/src/app/[variants]/(main)/agent/profile/features/ProfileEditor/index.tsx +16 -2
- package/src/app/[variants]/(main)/group/profile/features/AgentSettings/Content.tsx +140 -0
- package/src/app/[variants]/(main)/group/profile/features/AgentSettings/index.tsx +36 -0
- package/src/app/[variants]/(main)/group/profile/features/GroupProfile/index.tsx +17 -2
- package/src/features/AgentSetting/AgentOpening/OpeningQuestions.tsx +4 -3
- package/src/features/AgentSetting/AgentOpening/index.tsx +0 -3
- package/src/features/Conversation/Messages/AgentCouncil/components/CouncilList.tsx +2 -2
- package/src/features/PageEditor/Copilot/Toolbar.tsx +21 -5
- package/src/features/ProfileEditor/AgentTool.tsx +21 -29
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,67 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.348](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.347...v2.0.0-next.348)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2026-01-23**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **copilot**: History popover not refreshing when agentId changes.
|
|
12
|
+
- **misc**: Fixed the agent group builder tools excaution edge case crash, fixed the group topic copy not right.
|
|
13
|
+
|
|
14
|
+
<br/>
|
|
15
|
+
|
|
16
|
+
<details>
|
|
17
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
18
|
+
|
|
19
|
+
#### What's fixed
|
|
20
|
+
|
|
21
|
+
- **copilot**: History popover not refreshing when agentId changes, closes [#11731](https://github.com/lobehub/lobe-chat/issues/11731) ([64f39e7](https://github.com/lobehub/lobe-chat/commit/64f39e7))
|
|
22
|
+
- **misc**: Fixed the agent group builder tools excaution edge case crash, closes [#11735](https://github.com/lobehub/lobe-chat/issues/11735) ([5de4742](https://github.com/lobehub/lobe-chat/commit/5de4742))
|
|
23
|
+
- **misc**: Fixed the group topic copy not right, closes [#11730](https://github.com/lobehub/lobe-chat/issues/11730) ([282c1fb](https://github.com/lobehub/lobe-chat/commit/282c1fb))
|
|
24
|
+
|
|
25
|
+
</details>
|
|
26
|
+
|
|
27
|
+
<div align="right">
|
|
28
|
+
|
|
29
|
+
[](#readme-top)
|
|
30
|
+
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
## [Version 2.0.0-next.347](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.346...v2.0.0-next.347)
|
|
34
|
+
|
|
35
|
+
<sup>Released on **2026-01-23**</sup>
|
|
36
|
+
|
|
37
|
+
#### 🐛 Bug Fixes
|
|
38
|
+
|
|
39
|
+
- **misc**: Add advace config back in agent/group profiles.
|
|
40
|
+
|
|
41
|
+
#### 💄 Styles
|
|
42
|
+
|
|
43
|
+
- **misc**: Move plugin store button outside scroll container.
|
|
44
|
+
|
|
45
|
+
<br/>
|
|
46
|
+
|
|
47
|
+
<details>
|
|
48
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
49
|
+
|
|
50
|
+
#### What's fixed
|
|
51
|
+
|
|
52
|
+
- **misc**: Add advace config back in agent/group profiles, closes [#11727](https://github.com/lobehub/lobe-chat/issues/11727) ([403175f](https://github.com/lobehub/lobe-chat/commit/403175f))
|
|
53
|
+
|
|
54
|
+
#### Styles
|
|
55
|
+
|
|
56
|
+
- **misc**: Move plugin store button outside scroll container, closes [#11728](https://github.com/lobehub/lobe-chat/issues/11728) ([c484d1a](https://github.com/lobehub/lobe-chat/commit/c484d1a))
|
|
57
|
+
|
|
58
|
+
</details>
|
|
59
|
+
|
|
60
|
+
<div align="right">
|
|
61
|
+
|
|
62
|
+
[](#readme-top)
|
|
63
|
+
|
|
64
|
+
</div>
|
|
65
|
+
|
|
5
66
|
## [Version 2.0.0-next.346](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.345...v2.0.0-next.346)
|
|
6
67
|
|
|
7
68
|
<sup>Released on **2026-01-23**</sup>
|
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {
|
|
4
|
+
"fixes": [
|
|
5
|
+
"Fixed the agent group builder tools excaution edge case crash, fixed the group topic copy not right."
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
"date": "2026-01-23",
|
|
9
|
+
"version": "2.0.0-next.348"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"children": {
|
|
13
|
+
"fixes": [
|
|
14
|
+
"Add advace config back in agent/group profiles."
|
|
15
|
+
],
|
|
16
|
+
"improvements": [
|
|
17
|
+
"Move plugin store button outside scroll container."
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"date": "2026-01-23",
|
|
21
|
+
"version": "2.0.0-next.347"
|
|
22
|
+
},
|
|
2
23
|
{
|
|
3
24
|
"children": {},
|
|
4
25
|
"date": "2026-01-23",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/lobehub",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.348",
|
|
4
4
|
"description": "LobeHub - an open-source,comprehensive AI Agent 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",
|
package/packages/builtin-tool-group-agent-builder/src/client/Inspector/BatchCreateAgents/index.tsx
CHANGED
|
@@ -81,7 +81,7 @@ export const BatchCreateAgentsInspector = memo<
|
|
|
81
81
|
{displayInfo && (
|
|
82
82
|
<>
|
|
83
83
|
<div className={styles.avatarGroup}>
|
|
84
|
-
{displayInfo.displayAgents
|
|
84
|
+
{displayInfo.displayAgents?.map((agent, index) => (
|
|
85
85
|
<Avatar
|
|
86
86
|
avatar={agent.avatar}
|
|
87
87
|
key={index}
|
|
@@ -2,7 +2,7 @@ import { eq, inArray } from 'drizzle-orm';
|
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
3
3
|
|
|
4
4
|
import { getTestDB } from '../../../core/getTestDB';
|
|
5
|
-
import { agents, messages, sessions, topics, users } from '../../../schemas';
|
|
5
|
+
import { agents, messagePlugins, messages, sessions, topics, users } from '../../../schemas';
|
|
6
6
|
import { LobeChatDatabase } from '../../../type';
|
|
7
7
|
import { CreateTopicParams, TopicModel } from '../../topic';
|
|
8
8
|
|
|
@@ -279,6 +279,129 @@ describe('TopicModel - Create', () => {
|
|
|
279
279
|
expect(duplicatedMessages[1].content).toBe('Assistant message');
|
|
280
280
|
});
|
|
281
281
|
|
|
282
|
+
it('should correctly map parentId references when duplicating messages', async () => {
|
|
283
|
+
const topicId = 'topic-with-parent-refs';
|
|
284
|
+
|
|
285
|
+
await serverDB.transaction(async (tx) => {
|
|
286
|
+
await tx.insert(topics).values({ id: topicId, sessionId, userId, title: 'Original Topic' });
|
|
287
|
+
await tx.insert(messages).values([
|
|
288
|
+
{ id: 'msg1', role: 'user', topicId, userId, content: 'First message', parentId: null },
|
|
289
|
+
{
|
|
290
|
+
id: 'msg2',
|
|
291
|
+
role: 'assistant',
|
|
292
|
+
topicId,
|
|
293
|
+
userId,
|
|
294
|
+
content: 'Reply to first',
|
|
295
|
+
parentId: 'msg1',
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
id: 'msg3',
|
|
299
|
+
role: 'tool',
|
|
300
|
+
topicId,
|
|
301
|
+
userId,
|
|
302
|
+
content: 'Tool response',
|
|
303
|
+
parentId: 'msg2',
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
id: 'msg4',
|
|
307
|
+
role: 'assistant',
|
|
308
|
+
topicId,
|
|
309
|
+
userId,
|
|
310
|
+
content: 'Final message',
|
|
311
|
+
parentId: 'msg3',
|
|
312
|
+
},
|
|
313
|
+
]);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const { topic: duplicatedTopic, messages: duplicatedMessages } = await topicModel.duplicate(
|
|
317
|
+
topicId,
|
|
318
|
+
'Duplicated Topic',
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
expect(duplicatedMessages).toHaveLength(4);
|
|
322
|
+
|
|
323
|
+
const msgMap = new Map(duplicatedMessages.map((m) => [m.content, m]));
|
|
324
|
+
const newMsg1 = msgMap.get('First message')!;
|
|
325
|
+
const newMsg2 = msgMap.get('Reply to first')!;
|
|
326
|
+
const newMsg3 = msgMap.get('Tool response')!;
|
|
327
|
+
const newMsg4 = msgMap.get('Final message')!;
|
|
328
|
+
|
|
329
|
+
expect(newMsg1.parentId).toBeNull();
|
|
330
|
+
expect(newMsg2.parentId).toBe(newMsg1.id);
|
|
331
|
+
expect(newMsg3.parentId).toBe(newMsg2.id);
|
|
332
|
+
expect(newMsg4.parentId).toBe(newMsg3.id);
|
|
333
|
+
|
|
334
|
+
expect(newMsg1.id).not.toBe('msg1');
|
|
335
|
+
expect(newMsg2.id).not.toBe('msg2');
|
|
336
|
+
expect(newMsg3.id).not.toBe('msg3');
|
|
337
|
+
expect(newMsg4.id).not.toBe('msg4');
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('should correctly map tool_call_id when duplicating messages with tools', async () => {
|
|
341
|
+
const topicId = 'topic-with-tools';
|
|
342
|
+
const originalToolId = 'toolu_original_123';
|
|
343
|
+
|
|
344
|
+
await serverDB.transaction(async (tx) => {
|
|
345
|
+
await tx.insert(topics).values({ id: topicId, sessionId, userId, title: 'Original Topic' });
|
|
346
|
+
|
|
347
|
+
// Insert assistant message with tools
|
|
348
|
+
await tx.insert(messages).values({
|
|
349
|
+
id: 'msg1',
|
|
350
|
+
role: 'assistant',
|
|
351
|
+
topicId,
|
|
352
|
+
userId,
|
|
353
|
+
content: 'Using tool',
|
|
354
|
+
parentId: null,
|
|
355
|
+
tools: [{ id: originalToolId, type: 'builtin', apiName: 'broadcast' }],
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Insert tool message
|
|
359
|
+
await tx.insert(messages).values({
|
|
360
|
+
id: 'msg2',
|
|
361
|
+
role: 'tool',
|
|
362
|
+
topicId,
|
|
363
|
+
userId,
|
|
364
|
+
content: 'Tool response',
|
|
365
|
+
parentId: 'msg1',
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
// Insert messagePlugins entry
|
|
369
|
+
await tx.insert(messagePlugins).values({
|
|
370
|
+
id: 'msg2',
|
|
371
|
+
userId,
|
|
372
|
+
toolCallId: originalToolId,
|
|
373
|
+
apiName: 'broadcast',
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
const { topic: duplicatedTopic, messages: duplicatedMessages } = await topicModel.duplicate(
|
|
378
|
+
topicId,
|
|
379
|
+
'Duplicated Topic',
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
expect(duplicatedMessages).toHaveLength(2);
|
|
383
|
+
|
|
384
|
+
const msgMap = new Map(duplicatedMessages.map((m) => [m.role, m]));
|
|
385
|
+
const newAssistant = msgMap.get('assistant')!;
|
|
386
|
+
const newTool = msgMap.get('tool')!;
|
|
387
|
+
|
|
388
|
+
// Check that tools array has new IDs
|
|
389
|
+
expect(newAssistant.tools).toBeDefined();
|
|
390
|
+
const newTools = newAssistant.tools as any[];
|
|
391
|
+
expect(newTools).toHaveLength(1);
|
|
392
|
+
expect(newTools[0].id).not.toBe(originalToolId);
|
|
393
|
+
expect(newTools[0].id).toMatch(/^toolu_/);
|
|
394
|
+
|
|
395
|
+
// Check that messagePlugins was copied with new toolCallId
|
|
396
|
+
const newPlugin = await serverDB.query.messagePlugins.findFirst({
|
|
397
|
+
where: eq(messagePlugins.id, newTool.id),
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
expect(newPlugin).toBeDefined();
|
|
401
|
+
expect(newPlugin!.toolCallId).toBe(newTools[0].id);
|
|
402
|
+
expect(newPlugin!.toolCallId).not.toBe(originalToolId);
|
|
403
|
+
});
|
|
404
|
+
|
|
282
405
|
it('should throw an error if the topic to duplicate does not exist', async () => {
|
|
283
406
|
const topicId = 'nonexistent-topic';
|
|
284
407
|
|
|
@@ -17,7 +17,14 @@ import {
|
|
|
17
17
|
sql,
|
|
18
18
|
} from 'drizzle-orm';
|
|
19
19
|
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
TopicItem,
|
|
22
|
+
agents,
|
|
23
|
+
agentsToSessions,
|
|
24
|
+
messagePlugins,
|
|
25
|
+
messages,
|
|
26
|
+
topics,
|
|
27
|
+
} from '../schemas';
|
|
21
28
|
import { LobeChatDatabase } from '../type';
|
|
22
29
|
import { genEndDateWhere, genRangeWhere, genStartDateWhere, genWhere } from '../utils/genWhere';
|
|
23
30
|
import { idGenerator } from '../utils/idGenerator';
|
|
@@ -498,28 +505,83 @@ export class TopicModel {
|
|
|
498
505
|
})
|
|
499
506
|
.returning();
|
|
500
507
|
|
|
501
|
-
// Find messages associated with the original topic
|
|
508
|
+
// Find messages associated with the original topic, ordered by createdAt
|
|
502
509
|
const originalMessages = await tx
|
|
503
510
|
.select()
|
|
504
511
|
.from(messages)
|
|
505
|
-
.where(and(eq(messages.topicId, topicId), eq(messages.userId, this.userId)))
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
id
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
);
|
|
512
|
+
.where(and(eq(messages.topicId, topicId), eq(messages.userId, this.userId)))
|
|
513
|
+
.orderBy(messages.createdAt);
|
|
514
|
+
|
|
515
|
+
// Find all messagePlugins for this topic
|
|
516
|
+
const messageIds = originalMessages.map((m) => m.id);
|
|
517
|
+
const originalPlugins =
|
|
518
|
+
messageIds.length > 0
|
|
519
|
+
? await tx
|
|
520
|
+
.select()
|
|
521
|
+
.from(messagePlugins)
|
|
522
|
+
.where(inArray(messagePlugins.id, messageIds))
|
|
523
|
+
: [];
|
|
524
|
+
|
|
525
|
+
// Build oldId -> newId mapping for messages
|
|
526
|
+
const idMap = new Map<string, string>();
|
|
527
|
+
originalMessages.forEach((message) => {
|
|
528
|
+
idMap.set(message.id, idGenerator('messages'));
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// Build oldToolId -> newToolId mapping for tools
|
|
532
|
+
const toolIdMap = new Map<string, string>();
|
|
533
|
+
originalMessages.forEach((message) => {
|
|
534
|
+
if (message.tools && Array.isArray(message.tools)) {
|
|
535
|
+
(message.tools as any[]).forEach((tool: any) => {
|
|
536
|
+
if (tool.id) {
|
|
537
|
+
toolIdMap.set(tool.id, `toolu_${idGenerator('messages')}`);
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
// copy messages sequentially to respect foreign key constraints
|
|
544
|
+
const duplicatedMessages: DBMessageItem[] = [];
|
|
545
|
+
for (const message of originalMessages) {
|
|
546
|
+
const newId = idMap.get(message.id)!;
|
|
547
|
+
const newParentId = message.parentId ? idMap.get(message.parentId) || null : null;
|
|
548
|
+
|
|
549
|
+
// Update tool IDs in tools array
|
|
550
|
+
let newTools = message.tools;
|
|
551
|
+
if (newTools && Array.isArray(newTools)) {
|
|
552
|
+
newTools = (newTools as any[]).map((tool: any) => ({
|
|
553
|
+
...tool,
|
|
554
|
+
id: tool.id ? toolIdMap.get(tool.id) || tool.id : tool.id,
|
|
555
|
+
}));
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const result = (await tx
|
|
559
|
+
.insert(messages)
|
|
560
|
+
.values({
|
|
561
|
+
...message,
|
|
562
|
+
clientId: null,
|
|
563
|
+
id: newId,
|
|
564
|
+
parentId: newParentId,
|
|
565
|
+
topicId: duplicatedTopic.id,
|
|
566
|
+
tools: newTools,
|
|
567
|
+
})
|
|
568
|
+
.returning()) as DBMessageItem[];
|
|
569
|
+
|
|
570
|
+
duplicatedMessages.push(result[0]);
|
|
571
|
+
|
|
572
|
+
// Copy messagePlugins if exists for this message
|
|
573
|
+
const plugin = originalPlugins.find((p) => p.id === message.id);
|
|
574
|
+
if (plugin) {
|
|
575
|
+
const newToolCallId = plugin.toolCallId ? toolIdMap.get(plugin.toolCallId) || null : null;
|
|
576
|
+
|
|
577
|
+
await tx.insert(messagePlugins).values({
|
|
578
|
+
...plugin,
|
|
579
|
+
id: newId,
|
|
580
|
+
clientId: null,
|
|
581
|
+
toolCallId: newToolCallId,
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
}
|
|
523
585
|
|
|
524
586
|
return {
|
|
525
587
|
messages: duplicatedMessages,
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Avatar, Block, Flexbox, Icon, Text } from '@lobehub/ui';
|
|
4
|
+
import { useTheme } from 'antd-style';
|
|
5
|
+
import type { ItemType } from 'antd/es/menu/interface';
|
|
6
|
+
import isEqual from 'fast-deep-equal';
|
|
7
|
+
import { BrainIcon, MessageSquareHeartIcon, Settings2Icon } from 'lucide-react';
|
|
8
|
+
import { memo, useMemo, useState } from 'react';
|
|
9
|
+
import { useTranslation } from 'react-i18next';
|
|
10
|
+
|
|
11
|
+
import Menu from '@/components/Menu';
|
|
12
|
+
import { DEFAULT_AVATAR, DEFAULT_INBOX_AVATAR } from '@/const/meta';
|
|
13
|
+
import { AgentSettings as Settings } from '@/features/AgentSetting';
|
|
14
|
+
import { useAgentStore } from '@/store/agent';
|
|
15
|
+
import { agentSelectors, builtinAgentSelectors } from '@/store/agent/selectors';
|
|
16
|
+
import { ChatSettingsTabs } from '@/store/global/initialState';
|
|
17
|
+
|
|
18
|
+
const Content = memo(() => {
|
|
19
|
+
const { t } = useTranslation('setting');
|
|
20
|
+
const theme = useTheme();
|
|
21
|
+
const [agentId, isInbox] = useAgentStore((s) => [
|
|
22
|
+
s.activeAgentId,
|
|
23
|
+
builtinAgentSelectors.isInboxAgent(s),
|
|
24
|
+
]);
|
|
25
|
+
const config = useAgentStore(agentSelectors.currentAgentConfig, isEqual);
|
|
26
|
+
const meta = useAgentStore(agentSelectors.currentAgentMeta, isEqual);
|
|
27
|
+
const [tab, setTab] = useState(ChatSettingsTabs.Chat);
|
|
28
|
+
|
|
29
|
+
const updateAgentConfig = async (config: any) => {
|
|
30
|
+
if (!agentId) return;
|
|
31
|
+
await useAgentStore.getState().optimisticUpdateAgentConfig(agentId, config);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const updateAgentMeta = async (meta: any) => {
|
|
35
|
+
if (!agentId) return;
|
|
36
|
+
await useAgentStore.getState().optimisticUpdateAgentMeta(agentId, meta);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const menuItems: ItemType[] = useMemo(
|
|
40
|
+
() =>
|
|
41
|
+
[
|
|
42
|
+
{
|
|
43
|
+
icon: <Icon icon={Settings2Icon} />,
|
|
44
|
+
key: ChatSettingsTabs.Chat,
|
|
45
|
+
label: t('agentTab.chat'),
|
|
46
|
+
},
|
|
47
|
+
!isInbox
|
|
48
|
+
? {
|
|
49
|
+
icon: <Icon icon={MessageSquareHeartIcon} />,
|
|
50
|
+
key: ChatSettingsTabs.Opening,
|
|
51
|
+
label: t('agentTab.opening'),
|
|
52
|
+
}
|
|
53
|
+
: null,
|
|
54
|
+
{
|
|
55
|
+
icon: <Icon icon={BrainIcon} />,
|
|
56
|
+
key: ChatSettingsTabs.Modal,
|
|
57
|
+
label: t('agentTab.modal'),
|
|
58
|
+
},
|
|
59
|
+
].filter(Boolean) as ItemType[],
|
|
60
|
+
[t, isInbox],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const displayTitle = isInbox ? 'Lobe AI' : meta.title || t('defaultSession', { ns: 'common' });
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<Flexbox
|
|
67
|
+
direction="horizontal"
|
|
68
|
+
height="100%"
|
|
69
|
+
style={{
|
|
70
|
+
padding: 0,
|
|
71
|
+
position: 'relative',
|
|
72
|
+
}}
|
|
73
|
+
>
|
|
74
|
+
<Flexbox
|
|
75
|
+
height={'100%'}
|
|
76
|
+
paddingBlock={24}
|
|
77
|
+
paddingInline={8}
|
|
78
|
+
style={{
|
|
79
|
+
background: theme.colorBgLayout,
|
|
80
|
+
borderRight: `1px solid ${theme.colorBorderSecondary}`,
|
|
81
|
+
}}
|
|
82
|
+
width={200}
|
|
83
|
+
>
|
|
84
|
+
<Block
|
|
85
|
+
align={'center'}
|
|
86
|
+
gap={8}
|
|
87
|
+
horizontal
|
|
88
|
+
paddingBlock={'14px 16px'}
|
|
89
|
+
paddingInline={4}
|
|
90
|
+
style={{
|
|
91
|
+
overflow: 'hidden',
|
|
92
|
+
}}
|
|
93
|
+
variant={'borderless'}
|
|
94
|
+
>
|
|
95
|
+
<Avatar
|
|
96
|
+
avatar={isInbox ? DEFAULT_INBOX_AVATAR : meta.avatar || DEFAULT_AVATAR}
|
|
97
|
+
background={meta.backgroundColor || undefined}
|
|
98
|
+
shape={'square'}
|
|
99
|
+
size={28}
|
|
100
|
+
/>
|
|
101
|
+
<Text ellipsis weight={500}>
|
|
102
|
+
{displayTitle}
|
|
103
|
+
</Text>
|
|
104
|
+
</Block>
|
|
105
|
+
<Menu
|
|
106
|
+
items={menuItems}
|
|
107
|
+
onClick={({ key }) => setTab(key as ChatSettingsTabs)}
|
|
108
|
+
selectable
|
|
109
|
+
selectedKeys={[tab]}
|
|
110
|
+
style={{ width: '100%' }}
|
|
111
|
+
/>
|
|
112
|
+
</Flexbox>
|
|
113
|
+
<Flexbox
|
|
114
|
+
flex={1}
|
|
115
|
+
paddingBlock={24}
|
|
116
|
+
paddingInline={64}
|
|
117
|
+
style={{ overflow: 'scroll', width: '100%' }}
|
|
118
|
+
>
|
|
119
|
+
<Settings
|
|
120
|
+
config={config}
|
|
121
|
+
id={agentId}
|
|
122
|
+
loading={false}
|
|
123
|
+
meta={meta}
|
|
124
|
+
onConfigChange={updateAgentConfig}
|
|
125
|
+
onMetaChange={updateAgentMeta}
|
|
126
|
+
tab={tab}
|
|
127
|
+
/>
|
|
128
|
+
</Flexbox>
|
|
129
|
+
</Flexbox>
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
export default Content;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Modal } from '@lobehub/ui';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
|
|
6
|
+
import { useAgentStore } from '@/store/agent';
|
|
7
|
+
|
|
8
|
+
import Content from './Content';
|
|
9
|
+
|
|
10
|
+
const AgentSettings = memo(() => {
|
|
11
|
+
const showAgentSetting = useAgentStore((s) => s.showAgentSetting);
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<Modal
|
|
15
|
+
centered
|
|
16
|
+
footer={null}
|
|
17
|
+
onCancel={() => useAgentStore.setState({ showAgentSetting: false })}
|
|
18
|
+
open={showAgentSetting}
|
|
19
|
+
styles={{
|
|
20
|
+
body: {
|
|
21
|
+
height: '60vh',
|
|
22
|
+
overflow: 'scroll',
|
|
23
|
+
padding: 0,
|
|
24
|
+
position: 'relative',
|
|
25
|
+
},
|
|
26
|
+
}}
|
|
27
|
+
title={null}
|
|
28
|
+
width={960}
|
|
29
|
+
>
|
|
30
|
+
<Content />
|
|
31
|
+
</Modal>
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export default AgentSettings;
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
import { ENABLE_BUSINESS_FEATURES } from '@lobechat/business-const';
|
|
4
4
|
import { Button, Flexbox } from '@lobehub/ui';
|
|
5
5
|
import { Divider } from 'antd';
|
|
6
|
+
import { useTheme } from 'antd-style';
|
|
6
7
|
import isEqual from 'fast-deep-equal';
|
|
7
|
-
import { Clock, PlayIcon } from 'lucide-react';
|
|
8
|
+
import { Clock, PlayIcon, Settings2Icon } from 'lucide-react';
|
|
8
9
|
import React, { memo, useCallback } from 'react';
|
|
9
10
|
import { useTranslation } from 'react-i18next';
|
|
10
11
|
import urlJoin from 'url-join';
|
|
@@ -16,6 +17,7 @@ import { agentSelectors } from '@/store/agent/selectors';
|
|
|
16
17
|
import { useChatStore } from '@/store/chat';
|
|
17
18
|
|
|
18
19
|
import AgentCronJobs from '../AgentCronJobs';
|
|
20
|
+
import AgentSettings from '../AgentSettings';
|
|
19
21
|
import EditorCanvas from '../EditorCanvas';
|
|
20
22
|
import AgentPublishButton from '../Header/AgentPublishButton';
|
|
21
23
|
import AgentHeader from './AgentHeader';
|
|
@@ -23,6 +25,7 @@ import AgentTool from './AgentTool';
|
|
|
23
25
|
|
|
24
26
|
const ProfileEditor = memo(() => {
|
|
25
27
|
const { t } = useTranslation('setting');
|
|
28
|
+
const theme = useTheme();
|
|
26
29
|
const config = useAgentStore(agentSelectors.currentAgentConfig, isEqual);
|
|
27
30
|
const updateConfig = useAgentStore((s) => s.updateAgentConfig);
|
|
28
31
|
const agentId = useAgentStore((s) => s.activeAgentId);
|
|
@@ -44,7 +47,7 @@ const ProfileEditor = memo(() => {
|
|
|
44
47
|
>
|
|
45
48
|
{/* Header: Avatar + Name + Description */}
|
|
46
49
|
<AgentHeader />
|
|
47
|
-
{/* Config Bar: Model Selector */}
|
|
50
|
+
{/* Config Bar: Model Selector + Settings Button */}
|
|
48
51
|
<Flexbox
|
|
49
52
|
align={'center'}
|
|
50
53
|
gap={8}
|
|
@@ -59,6 +62,15 @@ const ProfileEditor = memo(() => {
|
|
|
59
62
|
provider: config.provider,
|
|
60
63
|
}}
|
|
61
64
|
/>
|
|
65
|
+
<Button
|
|
66
|
+
icon={Settings2Icon}
|
|
67
|
+
onClick={() => useAgentStore.setState({ showAgentSetting: true })}
|
|
68
|
+
size={'small'}
|
|
69
|
+
style={{ color: theme.colorTextSecondary }}
|
|
70
|
+
type={'text'}
|
|
71
|
+
>
|
|
72
|
+
{t('advancedSettings')}
|
|
73
|
+
</Button>
|
|
62
74
|
</Flexbox>
|
|
63
75
|
<AgentTool />
|
|
64
76
|
<Flexbox
|
|
@@ -93,6 +105,8 @@ const ProfileEditor = memo(() => {
|
|
|
93
105
|
<EditorCanvas />
|
|
94
106
|
{/* Agent Cron Jobs Display (only show if jobs exist) */}
|
|
95
107
|
{ENABLE_BUSINESS_FEATURES && <AgentCronJobs />}
|
|
108
|
+
{/* Advanced Settings Modal */}
|
|
109
|
+
<AgentSettings />
|
|
96
110
|
</>
|
|
97
111
|
);
|
|
98
112
|
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Avatar, Block, Flexbox, Icon, Text } from '@lobehub/ui';
|
|
4
|
+
import { useTheme } from 'antd-style';
|
|
5
|
+
import type { ItemType } from 'antd/es/menu/interface';
|
|
6
|
+
import { MessageSquareHeartIcon } from 'lucide-react';
|
|
7
|
+
import { memo, useMemo, useState } from 'react';
|
|
8
|
+
import { useTranslation } from 'react-i18next';
|
|
9
|
+
|
|
10
|
+
import Menu from '@/components/Menu';
|
|
11
|
+
import { DEFAULT_AVATAR } from '@/const/meta';
|
|
12
|
+
import { AgentSettings as Settings } from '@/features/AgentSetting';
|
|
13
|
+
import { useAgentGroupStore } from '@/store/agentGroup';
|
|
14
|
+
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
|
15
|
+
import { ChatSettingsTabs } from '@/store/global/initialState';
|
|
16
|
+
|
|
17
|
+
const Content = memo(() => {
|
|
18
|
+
const { t } = useTranslation('setting');
|
|
19
|
+
const theme = useTheme();
|
|
20
|
+
const groupId = useAgentGroupStore(agentGroupSelectors.activeGroupId);
|
|
21
|
+
const currentGroup = useAgentGroupStore(agentGroupSelectors.currentGroup);
|
|
22
|
+
const [tab] = useState(ChatSettingsTabs.Opening);
|
|
23
|
+
|
|
24
|
+
const updateGroupConfig = async (config: any) => {
|
|
25
|
+
if (!groupId) return;
|
|
26
|
+
// Only update openingMessage and openingQuestions
|
|
27
|
+
const groupConfig = {
|
|
28
|
+
openingMessage: config.openingMessage,
|
|
29
|
+
openingQuestions: config.openingQuestions,
|
|
30
|
+
};
|
|
31
|
+
await useAgentGroupStore.getState().updateGroupConfig(groupConfig);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const updateGroupMeta = async (meta: any) => {
|
|
35
|
+
if (!groupId) return;
|
|
36
|
+
await useAgentGroupStore.getState().updateGroup(groupId, meta);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Convert group config to agent config format for AgentSettings component
|
|
40
|
+
const agentConfig = useMemo(
|
|
41
|
+
() =>
|
|
42
|
+
({
|
|
43
|
+
chatConfig: {},
|
|
44
|
+
model: '',
|
|
45
|
+
openingMessage: currentGroup?.config?.openingMessage,
|
|
46
|
+
openingQuestions: currentGroup?.config?.openingQuestions,
|
|
47
|
+
params: {},
|
|
48
|
+
systemRole: '',
|
|
49
|
+
tts: {},
|
|
50
|
+
}) as any,
|
|
51
|
+
[currentGroup?.config],
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const agentMeta = useMemo(
|
|
55
|
+
() => ({
|
|
56
|
+
avatar: currentGroup?.avatar || undefined,
|
|
57
|
+
backgroundColor: currentGroup?.backgroundColor || undefined,
|
|
58
|
+
description: currentGroup?.description || undefined,
|
|
59
|
+
tags: [] as string[],
|
|
60
|
+
title: currentGroup?.title || undefined,
|
|
61
|
+
}),
|
|
62
|
+
[currentGroup],
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const menuItems: ItemType[] = useMemo(
|
|
66
|
+
() => [
|
|
67
|
+
{
|
|
68
|
+
icon: <Icon icon={MessageSquareHeartIcon} />,
|
|
69
|
+
key: ChatSettingsTabs.Opening,
|
|
70
|
+
label: t('agentTab.opening'),
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
[t],
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const displayTitle = currentGroup?.title || t('defaultSession', { ns: 'common' });
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<Flexbox
|
|
80
|
+
direction="horizontal"
|
|
81
|
+
height="100%"
|
|
82
|
+
style={{
|
|
83
|
+
padding: 0,
|
|
84
|
+
position: 'relative',
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
<Flexbox
|
|
88
|
+
height={'100%'}
|
|
89
|
+
paddingBlock={24}
|
|
90
|
+
paddingInline={8}
|
|
91
|
+
style={{
|
|
92
|
+
background: theme.colorBgLayout,
|
|
93
|
+
borderRight: `1px solid ${theme.colorBorderSecondary}`,
|
|
94
|
+
}}
|
|
95
|
+
width={200}
|
|
96
|
+
>
|
|
97
|
+
<Block
|
|
98
|
+
align={'center'}
|
|
99
|
+
gap={8}
|
|
100
|
+
horizontal
|
|
101
|
+
paddingBlock={'14px 16px'}
|
|
102
|
+
paddingInline={4}
|
|
103
|
+
style={{
|
|
104
|
+
overflow: 'hidden',
|
|
105
|
+
}}
|
|
106
|
+
variant={'borderless'}
|
|
107
|
+
>
|
|
108
|
+
<Avatar
|
|
109
|
+
avatar={currentGroup?.avatar || DEFAULT_AVATAR}
|
|
110
|
+
background={currentGroup?.backgroundColor || undefined}
|
|
111
|
+
shape={'square'}
|
|
112
|
+
size={28}
|
|
113
|
+
/>
|
|
114
|
+
<Text ellipsis weight={500}>
|
|
115
|
+
{displayTitle}
|
|
116
|
+
</Text>
|
|
117
|
+
</Block>
|
|
118
|
+
<Menu items={menuItems} selectable selectedKeys={[tab]} style={{ width: '100%' }} />
|
|
119
|
+
</Flexbox>
|
|
120
|
+
<Flexbox
|
|
121
|
+
flex={1}
|
|
122
|
+
paddingBlock={24}
|
|
123
|
+
paddingInline={64}
|
|
124
|
+
style={{ overflow: 'scroll', width: '100%' }}
|
|
125
|
+
>
|
|
126
|
+
<Settings
|
|
127
|
+
config={agentConfig}
|
|
128
|
+
id={groupId}
|
|
129
|
+
loading={false}
|
|
130
|
+
meta={agentMeta}
|
|
131
|
+
onConfigChange={updateGroupConfig}
|
|
132
|
+
onMetaChange={updateGroupMeta}
|
|
133
|
+
tab={tab}
|
|
134
|
+
/>
|
|
135
|
+
</Flexbox>
|
|
136
|
+
</Flexbox>
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
export default Content;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Modal } from '@lobehub/ui';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
|
|
6
|
+
import Content from './Content';
|
|
7
|
+
|
|
8
|
+
interface AgentSettingsProps {
|
|
9
|
+
onCancel: () => void;
|
|
10
|
+
open: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const AgentSettings = memo<AgentSettingsProps>(({ open, onCancel }) => {
|
|
14
|
+
return (
|
|
15
|
+
<Modal
|
|
16
|
+
centered
|
|
17
|
+
footer={null}
|
|
18
|
+
onCancel={onCancel}
|
|
19
|
+
open={open}
|
|
20
|
+
styles={{
|
|
21
|
+
body: {
|
|
22
|
+
height: '60vh',
|
|
23
|
+
overflow: 'scroll',
|
|
24
|
+
padding: 0,
|
|
25
|
+
position: 'relative',
|
|
26
|
+
},
|
|
27
|
+
}}
|
|
28
|
+
title={null}
|
|
29
|
+
width={960}
|
|
30
|
+
>
|
|
31
|
+
<Content />
|
|
32
|
+
</Modal>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export default AgentSettings;
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
import { Button, Flexbox } from '@lobehub/ui';
|
|
4
4
|
import { Divider } from 'antd';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { useTheme } from 'antd-style';
|
|
6
|
+
import { PlayIcon, Settings2Icon } from 'lucide-react';
|
|
7
|
+
import { memo, useCallback, useMemo, useState } from 'react';
|
|
7
8
|
import { useTranslation } from 'react-i18next';
|
|
8
9
|
import urlJoin from 'url-join';
|
|
9
10
|
|
|
@@ -13,12 +14,15 @@ import { useAgentGroupStore } from '@/store/agentGroup';
|
|
|
13
14
|
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
|
14
15
|
import { useGroupProfileStore } from '@/store/groupProfile';
|
|
15
16
|
|
|
17
|
+
import AgentSettings from '../AgentSettings';
|
|
16
18
|
import AutoSaveHint from '../Header/AutoSaveHint';
|
|
17
19
|
import GroupPublishButton from '../Header/GroupPublishButton';
|
|
18
20
|
import GroupHeader from './GroupHeader';
|
|
19
21
|
|
|
20
22
|
const GroupProfile = memo(() => {
|
|
21
23
|
const { t } = useTranslation(['setting', 'chat']);
|
|
24
|
+
const theme = useTheme();
|
|
25
|
+
const [showAgentSetting, setShowAgentSetting] = useState(false);
|
|
22
26
|
const groupId = useAgentGroupStore(agentGroupSelectors.activeGroupId);
|
|
23
27
|
const currentGroup = useAgentGroupStore(agentGroupSelectors.currentGroup);
|
|
24
28
|
const updateGroup = useAgentGroupStore((s) => s.updateGroup);
|
|
@@ -86,6 +90,15 @@ const GroupProfile = memo(() => {
|
|
|
86
90
|
{t('startConversation')}
|
|
87
91
|
</Button>
|
|
88
92
|
<GroupPublishButton />
|
|
93
|
+
<Button
|
|
94
|
+
icon={Settings2Icon}
|
|
95
|
+
onClick={() => setShowAgentSetting(true)}
|
|
96
|
+
size={'small'}
|
|
97
|
+
style={{ color: theme.colorTextSecondary }}
|
|
98
|
+
type={'text'}
|
|
99
|
+
>
|
|
100
|
+
{t('advancedSettings')}
|
|
101
|
+
</Button>
|
|
89
102
|
</Flexbox>
|
|
90
103
|
</Flexbox>
|
|
91
104
|
<Divider />
|
|
@@ -97,6 +110,8 @@ const GroupProfile = memo(() => {
|
|
|
97
110
|
onContentChange={onContentChange}
|
|
98
111
|
placeholder={t('group.profile.contentPlaceholder', { ns: 'chat' })}
|
|
99
112
|
/>
|
|
113
|
+
{/* Advanced Settings Modal */}
|
|
114
|
+
<AgentSettings onCancel={() => setShowAgentSetting(false)} open={showAgentSetting} />
|
|
100
115
|
</>
|
|
101
116
|
);
|
|
102
117
|
});
|
|
@@ -86,13 +86,14 @@ const OpeningQuestions = memo(() => {
|
|
|
86
86
|
const isRepeat = openingQuestions.includes(questionInput.trim());
|
|
87
87
|
|
|
88
88
|
return (
|
|
89
|
-
<Flexbox gap={8}>
|
|
90
|
-
<Flexbox gap={4}>
|
|
91
|
-
<Space.Compact>
|
|
89
|
+
<Flexbox gap={8} width={'100%'}>
|
|
90
|
+
<Flexbox gap={4} width={'100%'}>
|
|
91
|
+
<Space.Compact style={{ width: '100%' }}>
|
|
92
92
|
<Input
|
|
93
93
|
onChange={(e) => setQuestionInput(e.target.value)}
|
|
94
94
|
onPressEnter={addQuestion}
|
|
95
95
|
placeholder={t('settingOpening.openingQuestions.placeholder')}
|
|
96
|
+
style={{ flex: 1 }}
|
|
96
97
|
value={questionInput}
|
|
97
98
|
/>
|
|
98
99
|
<Button
|
|
@@ -4,8 +4,6 @@ import { Form } from '@lobehub/ui';
|
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
|
-
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
8
|
-
|
|
9
7
|
import OpeningMessage from './OpeningMessage';
|
|
10
8
|
import OpeningQuestions from './OpeningQuestions';
|
|
11
9
|
|
|
@@ -44,7 +42,6 @@ const AgentOpening = memo(() => {
|
|
|
44
42
|
]}
|
|
45
43
|
itemsType={'group'}
|
|
46
44
|
variant={'borderless'}
|
|
47
|
-
{...FORM_STYLE}
|
|
48
45
|
/>
|
|
49
46
|
);
|
|
50
47
|
});
|
|
@@ -62,7 +62,7 @@ const CouncilList = memo<CouncilListProps>(({ members, displayMode, activeTab })
|
|
|
62
62
|
minWidth: MIN_WIDTH * members.length + 32 + 32 * (members.length - 1),
|
|
63
63
|
}}
|
|
64
64
|
>
|
|
65
|
-
{members
|
|
65
|
+
{members?.map((member, idx) => {
|
|
66
66
|
if (!member) return null;
|
|
67
67
|
return (
|
|
68
68
|
<Fragment key={member.id}>
|
|
@@ -77,7 +77,7 @@ const CouncilList = memo<CouncilListProps>(({ members, displayMode, activeTab })
|
|
|
77
77
|
>
|
|
78
78
|
<CouncilMember index={idx} item={member} />
|
|
79
79
|
</Flexbox>
|
|
80
|
-
{idx < members
|
|
80
|
+
{idx < members?.length - 1 && (
|
|
81
81
|
<Divider
|
|
82
82
|
dashed
|
|
83
83
|
orientation={'vertical'}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ActionIcon, Block, Flexbox, Popover } from '@lobehub/ui';
|
|
2
2
|
import { createStaticStyles, cx } from 'antd-style';
|
|
3
3
|
import { ChevronsUpDownIcon, Clock3Icon, PanelRightCloseIcon, PlusIcon } from 'lucide-react';
|
|
4
|
-
import { Suspense, memo, useMemo, useState } from 'react';
|
|
4
|
+
import { Suspense, memo, useCallback, useMemo, useState } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
7
7
|
import AgentAvatar from '@/app/[variants]/(main)/home/_layout/Body/Agent/List/AgentItem/Avatar';
|
|
@@ -164,6 +164,15 @@ const CopilotToolbar = memo<CopilotToolbarProps>(({ agentId, isHovered }) => {
|
|
|
164
164
|
const setActiveAgentId = useAgentStore((s) => s.setActiveAgentId);
|
|
165
165
|
const [topicPopoverOpen, setTopicPopoverOpen] = useState(false);
|
|
166
166
|
|
|
167
|
+
const handleAgentChange = useCallback(
|
|
168
|
+
(id: string) => {
|
|
169
|
+
setActiveAgentId(id);
|
|
170
|
+
// Sync chatStore's activeAgentId to ensure topic selectors work correctly
|
|
171
|
+
useChatStore.setState({ activeAgentId: id });
|
|
172
|
+
},
|
|
173
|
+
[setActiveAgentId],
|
|
174
|
+
);
|
|
175
|
+
|
|
167
176
|
// Fetch topics for the agent builder
|
|
168
177
|
useChatStore((s) => s.useFetchTopics)(true, { agentId });
|
|
169
178
|
|
|
@@ -175,13 +184,15 @@ const CopilotToolbar = memo<CopilotToolbarProps>(({ agentId, isHovered }) => {
|
|
|
175
184
|
|
|
176
185
|
const [toggleRightPanel] = useGlobalStore((s) => [s.toggleRightPanel]);
|
|
177
186
|
|
|
178
|
-
|
|
187
|
+
// topics === undefined means still loading, topics.length === 0 means confirmed empty
|
|
188
|
+
const isLoadingTopics = topics === undefined;
|
|
189
|
+
const hideHistory = !isLoadingTopics && topics.length === 0;
|
|
179
190
|
|
|
180
191
|
return (
|
|
181
192
|
<NavHeader
|
|
182
193
|
left={
|
|
183
194
|
<Flexbox align="center" gap={8} horizontal>
|
|
184
|
-
<AgentSelector agentId={agentId} onAgentChange={
|
|
195
|
+
<AgentSelector agentId={agentId} onAgentChange={handleAgentChange} />
|
|
185
196
|
</Flexbox>
|
|
186
197
|
}
|
|
187
198
|
right={
|
|
@@ -218,7 +229,7 @@ const CopilotToolbar = memo<CopilotToolbarProps>(({ agentId, isHovered }) => {
|
|
|
218
229
|
</Flexbox>
|
|
219
230
|
}
|
|
220
231
|
onOpenChange={setTopicPopoverOpen}
|
|
221
|
-
open={topicPopoverOpen}
|
|
232
|
+
open={isLoadingTopics ? false : topicPopoverOpen}
|
|
222
233
|
placement="bottomRight"
|
|
223
234
|
styles={{
|
|
224
235
|
content: {
|
|
@@ -228,7 +239,12 @@ const CopilotToolbar = memo<CopilotToolbarProps>(({ agentId, isHovered }) => {
|
|
|
228
239
|
}}
|
|
229
240
|
trigger="click"
|
|
230
241
|
>
|
|
231
|
-
<ActionIcon
|
|
242
|
+
<ActionIcon
|
|
243
|
+
disabled={isLoadingTopics}
|
|
244
|
+
icon={Clock3Icon}
|
|
245
|
+
loading={isLoadingTopics}
|
|
246
|
+
size={DESKTOP_HEADER_ICON_SIZE}
|
|
247
|
+
/>
|
|
232
248
|
</Popover>
|
|
233
249
|
)}
|
|
234
250
|
</div>
|
|
@@ -44,13 +44,7 @@ const prefixCls = 'ant';
|
|
|
44
44
|
const styles = createStaticStyles(({ css }) => ({
|
|
45
45
|
dropdown: css`
|
|
46
46
|
overflow: hidden;
|
|
47
|
-
|
|
48
47
|
width: 100%;
|
|
49
|
-
border: 1px solid ${cssVar.colorBorderSecondary};
|
|
50
|
-
border-radius: ${cssVar.borderRadiusLG};
|
|
51
|
-
|
|
52
|
-
background: ${cssVar.colorBgElevated};
|
|
53
|
-
box-shadow: ${cssVar.boxShadowSecondary};
|
|
54
48
|
|
|
55
49
|
.${prefixCls}-dropdown-menu {
|
|
56
50
|
border-radius: 0 !important;
|
|
@@ -339,7 +333,9 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
339
333
|
() => [
|
|
340
334
|
// 原有的 builtin 工具
|
|
341
335
|
...filteredBuiltinList.map((item) => ({
|
|
342
|
-
icon:
|
|
336
|
+
icon: (
|
|
337
|
+
<Avatar avatar={item.meta.avatar} size={20} style={{ flex: 'none', marginRight: 0 }} />
|
|
338
|
+
),
|
|
343
339
|
key: item.identifier,
|
|
344
340
|
label: (
|
|
345
341
|
<ToolItem
|
|
@@ -412,18 +408,6 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
412
408
|
),
|
|
413
409
|
type: 'group',
|
|
414
410
|
},
|
|
415
|
-
{
|
|
416
|
-
type: 'divider',
|
|
417
|
-
},
|
|
418
|
-
{
|
|
419
|
-
extra: <Icon icon={ArrowRight} />,
|
|
420
|
-
icon: Store,
|
|
421
|
-
key: 'plugin-store',
|
|
422
|
-
label: t('tools.plugins.store'),
|
|
423
|
-
onClick: () => {
|
|
424
|
-
createSkillStoreModal();
|
|
425
|
-
},
|
|
426
|
-
},
|
|
427
411
|
],
|
|
428
412
|
[builtinItems, pluginItems, enablePluginCount, t],
|
|
429
413
|
);
|
|
@@ -557,7 +541,6 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
557
541
|
{/* Plugin Selector Dropdown - Using Action component pattern */}
|
|
558
542
|
<Suspense fallback={button}>
|
|
559
543
|
<ActionDropdown
|
|
560
|
-
maxHeight={500}
|
|
561
544
|
maxWidth={400}
|
|
562
545
|
menu={{
|
|
563
546
|
items: currentItems,
|
|
@@ -567,11 +550,10 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
567
550
|
overflowY: 'visible',
|
|
568
551
|
},
|
|
569
552
|
}}
|
|
570
|
-
minHeight={isKlavisEnabledInEnv || isLobehubSkillEnabled ? 500 : undefined}
|
|
571
553
|
minWidth={400}
|
|
572
554
|
placement={'bottomLeft'}
|
|
573
555
|
popupRender={(menu) => (
|
|
574
|
-
<
|
|
556
|
+
<Flexbox className={styles.dropdown} style={{ maxHeight: 500 }}>
|
|
575
557
|
{/* stopPropagation prevents dropdown's onClick from calling preventDefault on Segmented */}
|
|
576
558
|
<div className={styles.header} onClick={(e) => e.stopPropagation()}>
|
|
577
559
|
<Segmented
|
|
@@ -591,16 +573,26 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
591
573
|
value={effectiveTab}
|
|
592
574
|
/>
|
|
593
575
|
</div>
|
|
594
|
-
<div
|
|
595
|
-
|
|
576
|
+
<div className={styles.scroller} style={{ flex: 1 }}>
|
|
577
|
+
{menu}
|
|
578
|
+
</div>
|
|
579
|
+
<Flexbox
|
|
580
|
+
align="center"
|
|
581
|
+
gap={8}
|
|
582
|
+
horizontal
|
|
583
|
+
onClick={() => createSkillStoreModal()}
|
|
596
584
|
style={{
|
|
597
|
-
|
|
598
|
-
|
|
585
|
+
borderBlockStart: `1px solid ${cssVar.colorBorderSecondary}`,
|
|
586
|
+
cursor: 'pointer',
|
|
587
|
+
flex: 'none',
|
|
588
|
+
padding: cssVar.paddingSM,
|
|
599
589
|
}}
|
|
600
590
|
>
|
|
601
|
-
{
|
|
602
|
-
|
|
603
|
-
|
|
591
|
+
<Icon icon={Store} />
|
|
592
|
+
<span style={{ flex: 1 }}>{t('tools.plugins.store')}</span>
|
|
593
|
+
<Icon icon={ArrowRight} />
|
|
594
|
+
</Flexbox>
|
|
595
|
+
</Flexbox>
|
|
604
596
|
)}
|
|
605
597
|
trigger={'click'}
|
|
606
598
|
>
|