@lobehub/lobehub 2.0.0-next.287 → 2.0.0-next.288
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 +25 -0
- package/changelog/v1.json +9 -0
- package/locales/en-US/plugin.json +3 -5
- package/locales/zh-CN/plugin.json +3 -5
- package/locales/zh-CN/tool.json +2 -0
- package/package.json +1 -1
- package/packages/builtin-agents/src/agents/group-supervisor/index.ts +12 -1
- package/packages/builtin-agents/src/agents/group-supervisor/systemRole.ts +0 -7
- package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/EditLocalFile/index.tsx +93 -0
- package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/GlobLocalFiles/index.tsx +73 -0
- package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/GrepContent/index.tsx +69 -0
- package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/ListLocalFiles/index.tsx +68 -0
- package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/ReadLocalFile/index.tsx +74 -0
- package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/SearchLocalFiles/index.tsx +70 -0
- package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/WriteLocalFile/index.tsx +57 -0
- package/packages/builtin-tool-cloud-sandbox/src/client/Inspector/index.ts +14 -0
- package/packages/builtin-tool-cloud-sandbox/src/client/Render/WriteFile/index.tsx +54 -35
- package/packages/builtin-tool-cloud-sandbox/src/client/components/FilePathDisplay.tsx +52 -0
- package/packages/builtin-tool-group-management/src/client/Inspector/ExecuteTasks/index.tsx +90 -0
- package/packages/builtin-tool-group-management/src/client/Inspector/index.ts +2 -0
- package/packages/builtin-tool-group-management/src/client/Intervention/ExecuteTasks.tsx +237 -0
- package/packages/builtin-tool-group-management/src/client/Intervention/index.ts +4 -1
- package/packages/builtin-tool-group-management/src/client/Render/index.ts +1 -1
- package/packages/builtin-tool-group-management/src/client/Streaming/ExecuteTask/index.tsx +69 -0
- package/packages/builtin-tool-group-management/src/client/Streaming/ExecuteTasks/index.tsx +87 -0
- package/packages/builtin-tool-group-management/src/client/Streaming/index.ts +4 -0
- package/packages/builtin-tool-group-management/src/executor.test.ts +8 -311
- package/packages/builtin-tool-group-management/src/executor.ts +5 -160
- package/packages/builtin-tool-group-management/src/manifest.ts +50 -94
- package/packages/builtin-tool-group-management/src/systemRole.ts +251 -172
- package/packages/builtin-tool-group-management/src/types.ts +29 -40
- package/packages/context-engine/src/engine/messages/MessagesEngine.ts +6 -4
- package/packages/context-engine/src/engine/messages/types.ts +4 -4
- package/packages/context-engine/src/processors/GroupRoleTransform.ts +261 -0
- package/packages/context-engine/src/processors/__tests__/GroupRoleTransform.test.ts +553 -0
- package/packages/context-engine/src/processors/index.ts +2 -2
- package/packages/context-engine/src/providers/__tests__/GroupContextInjector.test.ts +4 -16
- package/packages/context-engine/src/providers/__tests__/__snapshots__/GroupContextInjector.test.ts.snap +23 -28
- package/packages/prompts/src/prompts/agentGroup/__snapshots__/index.test.ts.snap +0 -7
- package/packages/prompts/src/prompts/agentGroup/groupContext.ts +0 -7
- package/src/app/[variants]/(main)/group/features/Conversation/AgentWelcome/OpeningQuestions.tsx +4 -8
- package/src/app/[variants]/(main)/group/features/Conversation/MainChatInput/GroupChat.tsx +0 -3
- package/src/app/[variants]/(main)/group/features/Conversation/useGroupContext.ts +3 -0
- package/src/features/ChatInput/Desktop/index.tsx +1 -3
- package/src/features/Conversation/store/slices/message/action/crud.ts +2 -2
- package/src/locales/default/plugin.ts +3 -5
- package/src/locales/default/tool.ts +3 -0
- package/src/services/chat/mecha/agentConfigResolver.test.ts +160 -0
- package/src/services/chat/mecha/agentConfigResolver.ts +15 -3
- package/src/services/chat/mecha/contextEngineering.ts +2 -1
- package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +4 -2
- package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +2 -0
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +1 -18
- package/src/store/chat/slices/message/selectors/displayMessage.test.ts +24 -0
- package/src/store/chat/slices/message/selectors/displayMessage.ts +6 -1
- package/src/store/chat/slices/topic/action.test.ts +10 -4
- package/src/store/chat/slices/topic/action.ts +3 -2
- package/packages/context-engine/src/processors/GroupMessageSender.ts +0 -138
- package/packages/context-engine/src/processors/__tests__/GroupMessageSender.test.ts +0 -274
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import { CloudSandboxApiName } from '../../types';
|
|
2
|
+
import { EditLocalFileInspector } from './EditLocalFile';
|
|
2
3
|
import { ExecuteCodeInspector } from './ExecuteCode';
|
|
4
|
+
import { GlobLocalFilesInspector } from './GlobLocalFiles';
|
|
5
|
+
import { GrepContentInspector } from './GrepContent';
|
|
6
|
+
import { ListLocalFilesInspector } from './ListLocalFiles';
|
|
7
|
+
import { ReadLocalFileInspector } from './ReadLocalFile';
|
|
3
8
|
import { RunCommandInspector } from './RunCommand';
|
|
9
|
+
import { SearchLocalFilesInspector } from './SearchLocalFiles';
|
|
10
|
+
import { WriteLocalFileInspector } from './WriteLocalFile';
|
|
4
11
|
|
|
5
12
|
/**
|
|
6
13
|
* Code Interpreter Inspector Components Registry
|
|
7
14
|
*/
|
|
8
15
|
export const CloudSandboxInspectors = {
|
|
16
|
+
[CloudSandboxApiName.editLocalFile]: EditLocalFileInspector,
|
|
9
17
|
[CloudSandboxApiName.executeCode]: ExecuteCodeInspector,
|
|
18
|
+
[CloudSandboxApiName.globLocalFiles]: GlobLocalFilesInspector,
|
|
19
|
+
[CloudSandboxApiName.grepContent]: GrepContentInspector,
|
|
20
|
+
[CloudSandboxApiName.listLocalFiles]: ListLocalFilesInspector,
|
|
21
|
+
[CloudSandboxApiName.readLocalFile]: ReadLocalFileInspector,
|
|
10
22
|
[CloudSandboxApiName.runCommand]: RunCommandInspector,
|
|
23
|
+
[CloudSandboxApiName.searchLocalFiles]: SearchLocalFilesInspector,
|
|
24
|
+
[CloudSandboxApiName.writeLocalFile]: WriteLocalFileInspector,
|
|
11
25
|
};
|
|
@@ -1,54 +1,73 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons';
|
|
4
3
|
import { type BuiltinRenderProps } from '@lobechat/types';
|
|
5
|
-
import {
|
|
6
|
-
import { createStaticStyles, cssVar } from 'antd-style';
|
|
4
|
+
import { Block, Highlighter } from '@lobehub/ui';
|
|
7
5
|
import { memo } from 'react';
|
|
8
6
|
|
|
9
7
|
import { type WriteLocalFileState } from '../../../types';
|
|
10
8
|
|
|
11
|
-
const styles = createStaticStyles(({ css }) => ({
|
|
12
|
-
container: css`
|
|
13
|
-
overflow: hidden;
|
|
14
|
-
padding-inline: 8px 0;
|
|
15
|
-
`,
|
|
16
|
-
statusIcon: css`
|
|
17
|
-
font-size: 12px;
|
|
18
|
-
`,
|
|
19
|
-
}));
|
|
20
|
-
|
|
21
9
|
interface WriteLocalFileParams {
|
|
22
10
|
content: string;
|
|
23
11
|
createDirectories?: boolean;
|
|
24
12
|
path: string;
|
|
25
13
|
}
|
|
26
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Get file extension from path
|
|
17
|
+
*/
|
|
18
|
+
const getFileExtension = (path: string): string => {
|
|
19
|
+
const parts = path.split('.');
|
|
20
|
+
return parts.length > 1 ? parts.pop()?.toLowerCase() || 'text' : 'text';
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Map file extension to Highlighter language
|
|
25
|
+
*/
|
|
26
|
+
const getLanguageFromExtension = (ext: string): string => {
|
|
27
|
+
const languageMap: Record<string, string> = {
|
|
28
|
+
css: 'css',
|
|
29
|
+
go: 'go',
|
|
30
|
+
html: 'html',
|
|
31
|
+
java: 'java',
|
|
32
|
+
js: 'javascript',
|
|
33
|
+
json: 'json',
|
|
34
|
+
jsx: 'jsx',
|
|
35
|
+
md: 'markdown',
|
|
36
|
+
py: 'python',
|
|
37
|
+
rs: 'rust',
|
|
38
|
+
scss: 'scss',
|
|
39
|
+
sh: 'bash',
|
|
40
|
+
sql: 'sql',
|
|
41
|
+
ts: 'typescript',
|
|
42
|
+
tsx: 'tsx',
|
|
43
|
+
xml: 'xml',
|
|
44
|
+
yaml: 'yaml',
|
|
45
|
+
yml: 'yaml',
|
|
46
|
+
};
|
|
47
|
+
return languageMap[ext] || 'text';
|
|
48
|
+
};
|
|
49
|
+
|
|
27
50
|
const WriteFile = memo<BuiltinRenderProps<WriteLocalFileParams, WriteLocalFileState>>(
|
|
28
|
-
({ args
|
|
29
|
-
|
|
51
|
+
({ args }) => {
|
|
52
|
+
if (!args?.content) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const ext = getFileExtension(args.path);
|
|
57
|
+
const language = getLanguageFromExtension(ext);
|
|
30
58
|
|
|
31
59
|
return (
|
|
32
|
-
<
|
|
33
|
-
<
|
|
34
|
-
{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
{isSuccess ? `✅ Written to ${args.path}` : `❌ Failed to write ${args.path}`}
|
|
44
|
-
</Text>
|
|
45
|
-
{pluginState?.bytesWritten !== undefined && (
|
|
46
|
-
<Text as={'span'} code fontSize={12} type={'secondary'}>
|
|
47
|
-
({pluginState.bytesWritten} bytes)
|
|
48
|
-
</Text>
|
|
49
|
-
)}
|
|
50
|
-
</Flexbox>
|
|
51
|
-
</Flexbox>
|
|
60
|
+
<Block padding={8} variant={'outlined'}>
|
|
61
|
+
<Highlighter
|
|
62
|
+
language={language}
|
|
63
|
+
showLanguage
|
|
64
|
+
style={{ maxHeight: 400, overflow: 'auto' }}
|
|
65
|
+
variant={'borderless'}
|
|
66
|
+
wrap
|
|
67
|
+
>
|
|
68
|
+
{args.content}
|
|
69
|
+
</Highlighter>
|
|
70
|
+
</Block>
|
|
52
71
|
);
|
|
53
72
|
},
|
|
54
73
|
);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { MaterialFileTypeIcon } from '@lobehub/ui';
|
|
4
|
+
import { createStaticStyles, cssVar } from 'antd-style';
|
|
5
|
+
import path from 'path-browserify-esm';
|
|
6
|
+
import { memo, useMemo } from 'react';
|
|
7
|
+
|
|
8
|
+
const styles = createStaticStyles(({ css }) => ({
|
|
9
|
+
icon: css`
|
|
10
|
+
flex-shrink: 0;
|
|
11
|
+
margin-inline-end: 4px;
|
|
12
|
+
`,
|
|
13
|
+
text: css`
|
|
14
|
+
color: ${cssVar.colorText};
|
|
15
|
+
`,
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
interface FilePathDisplayProps {
|
|
19
|
+
filePath: string;
|
|
20
|
+
isDirectory?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const FilePathDisplay = memo<FilePathDisplayProps>(({ filePath, isDirectory }) => {
|
|
24
|
+
const { displayPath, name } = useMemo(() => {
|
|
25
|
+
if (!filePath) return { displayPath: '', name: '' };
|
|
26
|
+
const { base, dir } = path.parse(filePath);
|
|
27
|
+
const parentDir = path.basename(dir);
|
|
28
|
+
return {
|
|
29
|
+
displayPath: parentDir ? `${parentDir}/${base}` : base,
|
|
30
|
+
name: base,
|
|
31
|
+
};
|
|
32
|
+
}, [filePath]);
|
|
33
|
+
|
|
34
|
+
if (!filePath) return null;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<>
|
|
38
|
+
{name && (
|
|
39
|
+
<MaterialFileTypeIcon
|
|
40
|
+
className={styles.icon}
|
|
41
|
+
filename={name}
|
|
42
|
+
size={16}
|
|
43
|
+
type={isDirectory ? 'folder' : 'file'}
|
|
44
|
+
variant={'raw'}
|
|
45
|
+
/>
|
|
46
|
+
)}
|
|
47
|
+
{displayPath && <span className={styles.text}>{displayPath}</span>}
|
|
48
|
+
</>
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
FilePathDisplay.displayName = 'FilePathDisplay';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_AVATAR } from '@lobechat/const';
|
|
4
|
+
import type { AgentGroupMember, BuiltinInspectorProps } from '@lobechat/types';
|
|
5
|
+
import { Avatar, Flexbox } from '@lobehub/ui';
|
|
6
|
+
import { createStaticStyles, cx, useTheme } from 'antd-style';
|
|
7
|
+
import { memo, useMemo } from 'react';
|
|
8
|
+
import { useTranslation } from 'react-i18next';
|
|
9
|
+
|
|
10
|
+
import { useAgentGroupStore } from '@/store/agentGroup';
|
|
11
|
+
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
|
12
|
+
import { shinyTextStyles } from '@/styles';
|
|
13
|
+
|
|
14
|
+
import type { ExecuteTasksParams } from '../../../types';
|
|
15
|
+
|
|
16
|
+
const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
17
|
+
root: css`
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
display: flex;
|
|
20
|
+
gap: 8px;
|
|
21
|
+
align-items: center;
|
|
22
|
+
`,
|
|
23
|
+
title: css`
|
|
24
|
+
flex-shrink: 0;
|
|
25
|
+
color: ${cssVar.colorTextSecondary};
|
|
26
|
+
white-space: nowrap;
|
|
27
|
+
`,
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
export const ExecuteTasksInspector = memo<BuiltinInspectorProps<ExecuteTasksParams>>(
|
|
31
|
+
({ args, partialArgs, isArgumentsStreaming }) => {
|
|
32
|
+
const { t } = useTranslation('plugin');
|
|
33
|
+
|
|
34
|
+
const tasks = args?.tasks || partialArgs?.tasks || [];
|
|
35
|
+
const agentIds = useMemo(() => tasks.map((task) => task.agentId).filter(Boolean), [tasks]);
|
|
36
|
+
|
|
37
|
+
// Get active group ID and agents from store
|
|
38
|
+
const activeGroupId = useAgentGroupStore(agentGroupSelectors.activeGroupId);
|
|
39
|
+
const groupAgents = useAgentGroupStore((s) =>
|
|
40
|
+
activeGroupId ? agentGroupSelectors.getGroupAgents(activeGroupId)(s) : [],
|
|
41
|
+
);
|
|
42
|
+
const theme = useTheme();
|
|
43
|
+
|
|
44
|
+
// Get agent details for the task targets
|
|
45
|
+
const agents = useMemo(() => {
|
|
46
|
+
if (!agentIds.length || !groupAgents.length) return [];
|
|
47
|
+
return agentIds
|
|
48
|
+
.map((id) => groupAgents.find((agent) => agent.id === id))
|
|
49
|
+
.filter((agent): agent is AgentGroupMember => !!agent);
|
|
50
|
+
}, [agentIds, groupAgents]);
|
|
51
|
+
|
|
52
|
+
// Transform agents to Avatar.Group format
|
|
53
|
+
const avatarItems = useMemo(
|
|
54
|
+
() =>
|
|
55
|
+
agents.map((agent) => ({
|
|
56
|
+
avatar: agent.avatar || DEFAULT_AVATAR,
|
|
57
|
+
background: agent.backgroundColor || theme.colorBgContainer,
|
|
58
|
+
key: agent.id,
|
|
59
|
+
title: agent.title || undefined,
|
|
60
|
+
})),
|
|
61
|
+
[agents, theme.colorBgContainer],
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (isArgumentsStreaming && agents.length === 0) {
|
|
65
|
+
return (
|
|
66
|
+
<div className={cx(styles.root, shinyTextStyles.shinyText)}>
|
|
67
|
+
<span>{t('builtins.lobe-group-management.apiName.executeAgentTasks')}</span>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<Flexbox
|
|
74
|
+
align={'center'}
|
|
75
|
+
className={cx(styles.root, isArgumentsStreaming && shinyTextStyles.shinyText)}
|
|
76
|
+
gap={8}
|
|
77
|
+
horizontal
|
|
78
|
+
>
|
|
79
|
+
<span className={styles.title}>
|
|
80
|
+
{t('builtins.lobe-group-management.inspector.executeAgentTasks.title')}
|
|
81
|
+
</span>
|
|
82
|
+
{avatarItems.length > 0 && <Avatar.Group items={avatarItems} shape={'circle'} size={24} />}
|
|
83
|
+
</Flexbox>
|
|
84
|
+
);
|
|
85
|
+
},
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
ExecuteTasksInspector.displayName = 'ExecuteTasksInspector';
|
|
89
|
+
|
|
90
|
+
export default ExecuteTasksInspector;
|
|
@@ -2,6 +2,7 @@ import { type BuiltinInspector } from '@lobechat/types';
|
|
|
2
2
|
|
|
3
3
|
import { GroupManagementApiName } from '../../types';
|
|
4
4
|
import { BroadcastInspector } from './Broadcast';
|
|
5
|
+
import { ExecuteTasksInspector } from './ExecuteTasks';
|
|
5
6
|
import { SpeakInspector } from './Speak';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -12,5 +13,6 @@ import { SpeakInspector } from './Speak';
|
|
|
12
13
|
*/
|
|
13
14
|
export const GroupManagementInspectors: Record<string, BuiltinInspector> = {
|
|
14
15
|
[GroupManagementApiName.broadcast]: BroadcastInspector as BuiltinInspector,
|
|
16
|
+
[GroupManagementApiName.executeAgentTasks]: ExecuteTasksInspector as BuiltinInspector,
|
|
15
17
|
[GroupManagementApiName.speak]: SpeakInspector as BuiltinInspector,
|
|
16
18
|
};
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_AVATAR } from '@lobechat/const';
|
|
4
|
+
import { BuiltinInterventionProps } from '@lobechat/types';
|
|
5
|
+
import { Avatar, Flexbox, Icon, Tooltip } from '@lobehub/ui';
|
|
6
|
+
import { Collapse, Input, InputNumber } from 'antd';
|
|
7
|
+
import { createStaticStyles, useTheme } from 'antd-style';
|
|
8
|
+
import isEqual from 'fast-deep-equal';
|
|
9
|
+
import { Clock, Trash2 } from 'lucide-react';
|
|
10
|
+
import { ChangeEvent, memo, useCallback, useEffect, useState } from 'react';
|
|
11
|
+
import { useTranslation } from 'react-i18next';
|
|
12
|
+
|
|
13
|
+
import { useAgentGroupStore } from '@/store/agentGroup';
|
|
14
|
+
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
|
15
|
+
|
|
16
|
+
import type { ExecuteTasksParams, TaskItem } from '../../types';
|
|
17
|
+
|
|
18
|
+
const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
19
|
+
agentTitle: css`
|
|
20
|
+
font-size: 14px;
|
|
21
|
+
font-weight: 500;
|
|
22
|
+
color: ${cssVar.colorText};
|
|
23
|
+
`,
|
|
24
|
+
container: css`
|
|
25
|
+
padding-block: 12px;
|
|
26
|
+
border-radius: ${cssVar.borderRadius};
|
|
27
|
+
`,
|
|
28
|
+
deleteButton: css`
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
color: ${cssVar.colorTextTertiary};
|
|
31
|
+
transition: color 0.2s;
|
|
32
|
+
|
|
33
|
+
&:hover {
|
|
34
|
+
color: ${cssVar.colorError};
|
|
35
|
+
}
|
|
36
|
+
`,
|
|
37
|
+
taskCard: css`
|
|
38
|
+
.ant-collapse-header {
|
|
39
|
+
padding-block: 8px !important;
|
|
40
|
+
padding-inline: 12px !important;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.ant-collapse-content-box {
|
|
44
|
+
padding: 12px !important;
|
|
45
|
+
}
|
|
46
|
+
`,
|
|
47
|
+
taskTitle: css`
|
|
48
|
+
font-size: 13px;
|
|
49
|
+
font-weight: 500;
|
|
50
|
+
color: ${cssVar.colorText};
|
|
51
|
+
`,
|
|
52
|
+
timeoutInput: css`
|
|
53
|
+
width: 100px;
|
|
54
|
+
`,
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
const DEFAULT_TIMEOUT = 1_800_000; // 30 minutes
|
|
58
|
+
|
|
59
|
+
interface TaskEditorProps {
|
|
60
|
+
index: number;
|
|
61
|
+
onChange: (index: number, updates: Partial<TaskItem>) => void;
|
|
62
|
+
onDelete: (index: number) => void;
|
|
63
|
+
task: TaskItem;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const TaskEditor = memo<TaskEditorProps>(({ task, index, onChange, onDelete }) => {
|
|
67
|
+
const { t } = useTranslation('tool');
|
|
68
|
+
const theme = useTheme();
|
|
69
|
+
|
|
70
|
+
// Get agent info from store
|
|
71
|
+
const activeGroupId = useAgentGroupStore(agentGroupSelectors.activeGroupId);
|
|
72
|
+
const agent = useAgentGroupStore((s) =>
|
|
73
|
+
task.agentId && activeGroupId
|
|
74
|
+
? agentGroupSelectors.getAgentByIdFromGroup(activeGroupId, task.agentId)(s)
|
|
75
|
+
: undefined,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const handleTitleChange = useCallback(
|
|
79
|
+
(e: ChangeEvent<HTMLInputElement>) => {
|
|
80
|
+
onChange(index, { title: e.target.value });
|
|
81
|
+
},
|
|
82
|
+
[index, onChange],
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const handleInstructionChange = useCallback(
|
|
86
|
+
(e: ChangeEvent<HTMLTextAreaElement>) => {
|
|
87
|
+
onChange(index, { instruction: e.target.value });
|
|
88
|
+
},
|
|
89
|
+
[index, onChange],
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const handleTimeoutChange = useCallback(
|
|
93
|
+
(value: number | null) => {
|
|
94
|
+
if (value !== null) {
|
|
95
|
+
onChange(index, { timeout: value * 60 * 1000 });
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
[index, onChange],
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const handleDelete = useCallback(() => {
|
|
102
|
+
onDelete(index);
|
|
103
|
+
}, [index, onDelete]);
|
|
104
|
+
|
|
105
|
+
const header = (
|
|
106
|
+
<Flexbox align={'center'} gap={8} horizontal justify={'space-between'}>
|
|
107
|
+
<Flexbox align={'center'} flex={1} gap={8} horizontal style={{ minWidth: 0 }}>
|
|
108
|
+
<Avatar
|
|
109
|
+
avatar={agent?.avatar || DEFAULT_AVATAR}
|
|
110
|
+
background={agent?.backgroundColor || theme.colorBgContainer}
|
|
111
|
+
shape={'square'}
|
|
112
|
+
size={24}
|
|
113
|
+
/>
|
|
114
|
+
<span className={styles.taskTitle}>{task.title || agent?.title || 'Task'}</span>
|
|
115
|
+
</Flexbox>
|
|
116
|
+
<Flexbox align={'center'} gap={8} horizontal onClick={(e) => e.stopPropagation()}>
|
|
117
|
+
<Tooltip title={t('agentGroupManagement.executeTask.intervention.timeout')}>
|
|
118
|
+
<Clock size={14} />
|
|
119
|
+
</Tooltip>
|
|
120
|
+
<InputNumber
|
|
121
|
+
className={styles.timeoutInput}
|
|
122
|
+
max={120}
|
|
123
|
+
min={1}
|
|
124
|
+
onChange={handleTimeoutChange}
|
|
125
|
+
size={'small'}
|
|
126
|
+
suffix={t('agentGroupManagement.executeTask.intervention.timeoutUnit')}
|
|
127
|
+
value={Math.round((task.timeout || DEFAULT_TIMEOUT) / 60_000)}
|
|
128
|
+
variant={'filled'}
|
|
129
|
+
/>
|
|
130
|
+
<Icon
|
|
131
|
+
className={styles.deleteButton}
|
|
132
|
+
icon={Trash2}
|
|
133
|
+
onClick={handleDelete}
|
|
134
|
+
size={{ size: 16 }}
|
|
135
|
+
/>
|
|
136
|
+
</Flexbox>
|
|
137
|
+
</Flexbox>
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<Collapse
|
|
142
|
+
className={styles.taskCard}
|
|
143
|
+
defaultActiveKey={[index]}
|
|
144
|
+
items={[
|
|
145
|
+
{
|
|
146
|
+
children: (
|
|
147
|
+
<Flexbox gap={12}>
|
|
148
|
+
<Input
|
|
149
|
+
onChange={handleTitleChange}
|
|
150
|
+
placeholder={t('agentGroupManagement.executeTasks.intervention.titlePlaceholder')}
|
|
151
|
+
value={task.title}
|
|
152
|
+
/>
|
|
153
|
+
<Input.TextArea
|
|
154
|
+
autoSize={{ maxRows: 8, minRows: 4 }}
|
|
155
|
+
onChange={handleInstructionChange}
|
|
156
|
+
placeholder={t(
|
|
157
|
+
'agentGroupManagement.executeTasks.intervention.instructionPlaceholder',
|
|
158
|
+
)}
|
|
159
|
+
value={task.instruction}
|
|
160
|
+
/>
|
|
161
|
+
</Flexbox>
|
|
162
|
+
),
|
|
163
|
+
key: index,
|
|
164
|
+
label: header,
|
|
165
|
+
},
|
|
166
|
+
]}
|
|
167
|
+
/>
|
|
168
|
+
);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* ExecuteTasks Intervention Component
|
|
173
|
+
*
|
|
174
|
+
* Allows users to review and modify multiple tasks before execution.
|
|
175
|
+
*/
|
|
176
|
+
const ExecuteTasksIntervention = memo<BuiltinInterventionProps<ExecuteTasksParams>>(
|
|
177
|
+
({ args, onArgsChange, registerBeforeApprove }) => {
|
|
178
|
+
// Local state
|
|
179
|
+
const [tasks, setTasks] = useState<TaskItem[]>(args?.tasks || []);
|
|
180
|
+
const [hasChanges, setHasChanges] = useState(false);
|
|
181
|
+
|
|
182
|
+
// Sync local state when args change externally
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
if (!hasChanges) {
|
|
185
|
+
setTasks(args?.tasks || []);
|
|
186
|
+
}
|
|
187
|
+
}, [args?.tasks, hasChanges]);
|
|
188
|
+
|
|
189
|
+
// Handle task change
|
|
190
|
+
const handleTaskChange = useCallback((index: number, updates: Partial<TaskItem>) => {
|
|
191
|
+
setTasks((prev) => {
|
|
192
|
+
const newTasks = [...prev];
|
|
193
|
+
newTasks[index] = { ...newTasks[index], ...updates };
|
|
194
|
+
return newTasks;
|
|
195
|
+
});
|
|
196
|
+
setHasChanges(true);
|
|
197
|
+
}, []);
|
|
198
|
+
|
|
199
|
+
// Handle task delete
|
|
200
|
+
const handleTaskDelete = useCallback((index: number) => {
|
|
201
|
+
setTasks((prev) => prev.filter((_, i) => i !== index));
|
|
202
|
+
setHasChanges(true);
|
|
203
|
+
}, []);
|
|
204
|
+
|
|
205
|
+
// Save changes before approval
|
|
206
|
+
useEffect(() => {
|
|
207
|
+
if (!registerBeforeApprove) return;
|
|
208
|
+
|
|
209
|
+
const cleanup = registerBeforeApprove('executeTasks', async () => {
|
|
210
|
+
if (hasChanges && onArgsChange) {
|
|
211
|
+
await onArgsChange({ ...args, tasks });
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
return cleanup;
|
|
216
|
+
}, [registerBeforeApprove, hasChanges, tasks, args, onArgsChange]);
|
|
217
|
+
|
|
218
|
+
return (
|
|
219
|
+
<Flexbox className={styles.container} gap={12}>
|
|
220
|
+
{tasks.map((task, index) => (
|
|
221
|
+
<TaskEditor
|
|
222
|
+
index={index}
|
|
223
|
+
key={task.agentId || index}
|
|
224
|
+
onChange={handleTaskChange}
|
|
225
|
+
onDelete={handleTaskDelete}
|
|
226
|
+
task={task}
|
|
227
|
+
/>
|
|
228
|
+
))}
|
|
229
|
+
</Flexbox>
|
|
230
|
+
);
|
|
231
|
+
},
|
|
232
|
+
isEqual,
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
ExecuteTasksIntervention.displayName = 'ExecuteTasksIntervention';
|
|
236
|
+
|
|
237
|
+
export default ExecuteTasksIntervention;
|
|
@@ -2,6 +2,7 @@ import { BuiltinIntervention } from '@lobechat/types';
|
|
|
2
2
|
|
|
3
3
|
import { GroupManagementApiName } from '../../types';
|
|
4
4
|
import ExecuteTaskIntervention from './ExecuteTask';
|
|
5
|
+
import ExecuteTasksIntervention from './ExecuteTasks';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Group Management Tool Intervention Components Registry
|
|
@@ -10,7 +11,9 @@ import ExecuteTaskIntervention from './ExecuteTask';
|
|
|
10
11
|
* before the tool is executed.
|
|
11
12
|
*/
|
|
12
13
|
export const GroupManagementInterventions: Record<string, BuiltinIntervention> = {
|
|
13
|
-
[GroupManagementApiName.
|
|
14
|
+
[GroupManagementApiName.executeAgentTask]: ExecuteTaskIntervention as BuiltinIntervention,
|
|
15
|
+
[GroupManagementApiName.executeAgentTasks]: ExecuteTasksIntervention as BuiltinIntervention,
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
export { default as ExecuteTaskIntervention } from './ExecuteTask';
|
|
19
|
+
export { default as ExecuteTasksIntervention } from './ExecuteTasks';
|
|
@@ -8,7 +8,7 @@ import SpeakRender from './Speak';
|
|
|
8
8
|
*/
|
|
9
9
|
export const GroupManagementRenders = {
|
|
10
10
|
[GroupManagementApiName.broadcast]: BroadcastRender,
|
|
11
|
-
[GroupManagementApiName.
|
|
11
|
+
[GroupManagementApiName.executeAgentTask]: ExecuteTaskRender,
|
|
12
12
|
[GroupManagementApiName.speak]: SpeakRender,
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { DEFAULT_AVATAR } from '@lobechat/const';
|
|
4
|
+
import type { BuiltinStreamingProps } from '@lobechat/types';
|
|
5
|
+
import { Avatar, Flexbox, Markdown } from '@lobehub/ui';
|
|
6
|
+
import { createStaticStyles, useTheme } from 'antd-style';
|
|
7
|
+
import { memo } from 'react';
|
|
8
|
+
|
|
9
|
+
import { useAgentGroupStore } from '@/store/agentGroup';
|
|
10
|
+
import { agentGroupSelectors } from '@/store/agentGroup/selectors';
|
|
11
|
+
|
|
12
|
+
import type { ExecuteTaskParams } from '../../../types';
|
|
13
|
+
|
|
14
|
+
const styles = createStaticStyles(({ css, cssVar }) => ({
|
|
15
|
+
agentTitle: css`
|
|
16
|
+
font-size: 14px;
|
|
17
|
+
font-weight: 500;
|
|
18
|
+
color: ${cssVar.colorText};
|
|
19
|
+
`,
|
|
20
|
+
container: css`
|
|
21
|
+
padding: 12px;
|
|
22
|
+
border-radius: 8px;
|
|
23
|
+
background: ${cssVar.colorFillQuaternary};
|
|
24
|
+
`,
|
|
25
|
+
task: css`
|
|
26
|
+
font-size: 13px;
|
|
27
|
+
color: ${cssVar.colorTextSecondary};
|
|
28
|
+
`,
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
export const ExecuteTaskStreaming = memo<BuiltinStreamingProps<ExecuteTaskParams>>(({ args }) => {
|
|
32
|
+
const { agentId, task } = args || {};
|
|
33
|
+
const theme = useTheme();
|
|
34
|
+
|
|
35
|
+
// Get active group ID and agent from store
|
|
36
|
+
const activeGroupId = useAgentGroupStore(agentGroupSelectors.activeGroupId);
|
|
37
|
+
const agent = useAgentGroupStore((s) =>
|
|
38
|
+
activeGroupId && agentId
|
|
39
|
+
? agentGroupSelectors.getAgentByIdFromGroup(activeGroupId, agentId)(s)
|
|
40
|
+
: undefined,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
if (!task) return null;
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div className={styles.container}>
|
|
47
|
+
<Flexbox gap={8}>
|
|
48
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
49
|
+
<Avatar
|
|
50
|
+
avatar={agent?.avatar || DEFAULT_AVATAR}
|
|
51
|
+
background={agent?.backgroundColor || theme.colorBgContainer}
|
|
52
|
+
shape={'square'}
|
|
53
|
+
size={24}
|
|
54
|
+
/>
|
|
55
|
+
<span className={styles.agentTitle}>{agent?.title || 'Agent'}</span>
|
|
56
|
+
</Flexbox>
|
|
57
|
+
<div className={styles.task}>
|
|
58
|
+
<Markdown animated variant={'chat'}>
|
|
59
|
+
{task}
|
|
60
|
+
</Markdown>
|
|
61
|
+
</div>
|
|
62
|
+
</Flexbox>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
ExecuteTaskStreaming.displayName = 'ExecuteTaskStreaming';
|
|
68
|
+
|
|
69
|
+
export default ExecuteTaskStreaming;
|