feat(web): cluster

This commit is contained in:
zhaoying
2025-12-31 12:30:36 +08:00
parent 3560038894
commit 24d68de98c
7 changed files with 207 additions and 99 deletions

View File

@@ -725,6 +725,14 @@ export const en = {
quicklyForget: 'Quickly forget', quicklyForget: 'Quickly forget',
slowForgetting: 'Slow forgetting', slowForgetting: 'Slow forgetting',
currentConfig: 'Current Config', currentConfig: 'Current Config',
decay_constant: 'Decay Constant',
max_history_length: 'Max Access History Length',
forgetting_threshold: 'Forgetting Threshold',
min_days_since_access: 'Minimum Days Since Access',
enable_llm_summary: 'Enable LLM Summary Generation',
max_merge_batch_size: 'Max Merge Batch Size',
forgetting_interval_hours: 'Forgetting Interval Hours'
}, },
application: { application: {
searchPlaceholder: 'Search for applications or clusters', searchPlaceholder: 'Search for applications or clusters',
@@ -878,8 +886,6 @@ export const en = {
toolCalling: 'Tool Calling', toolCalling: 'Tool Calling',
toolCallingDesc: 'The main control agent calls sub agents as tools', toolCallingDesc: 'The main control agent calls sub agents as tools',
toolCallingFeature: 'Centralized control, suitable for structured workflow', toolCallingFeature: 'Centralized control, suitable for structured workflow',
handoffs: 'Handoffs',
handoffsDesc: 'Agents between dynamic transfer of control rights',
handoffsFeature: 'Decentralized control, suitable for complex conversation scenarios', handoffsFeature: 'Decentralized control, suitable for complex conversation scenarios',
recommend: 'Recommend', recommend: 'Recommend',
advanced: 'Advanced', advanced: 'Advanced',
@@ -1000,6 +1006,21 @@ export const en = {
promptChatPlaceholder: 'Describe the prompt you need, e.g.: I need a customer service assistant', promptChatPlaceholder: 'Describe the prompt you need, e.g.: I need a customer service assistant',
promptChatEmpty: 'No conversation content available', promptChatEmpty: 'No conversation content available',
promptEmpty: 'Describe your use case on the left, and the orchestration preview will be displayed here.', promptEmpty: 'Describe your use case on the left, and the orchestration preview will be displayed here.',
master: 'Supervisor Mode',
master_agent: 'Supervisor Mode',
master_agentDesc: 'Unified scheduling and management by the main Agent, with sub-Agents executing tasks assigned by the supervisor, suitable for scenarios requiring centralized control.',
handoffs: 'Collaboration Mode',
handoffsDesc: 'Multiple Agents collaborate equally, autonomously coordinating according to task requirements, suitable for complex scenarios requiring flexible interaction.',
masterConfig: 'Supervisor Configuration',
orchestrationMode: 'Task Assignment Strategy',
conditional: 'Intelligent Assignment',
sequential: 'Sequential Assignment',
parallel: 'Parallel Assignment',
aggregationStrategy: 'Result Aggregation Method',
merge: 'Complete Aggregation',
vote: 'Key Information Extraction',
priority: 'Structured Integration',
}, },
userMemory: { userMemory: {
userMemory: 'User Memory', userMemory: 'User Memory',
@@ -1355,15 +1376,15 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
last_health_check: 'Last Connection', last_health_check: 'Last Connection',
responseTime: 'Response Time', responseTime: 'Response Time',
status: { status: {
available: '可用', available: 'Available',
unconfigured: '未配置', unconfigured: 'Unconfigured',
configured_disabled: '已配置未启用', configured_disabled: 'Configured but Disabled',
error: '链接异常' error: 'Connection Error'
}, },
available_desc: 'API 已配置并启用', available_desc: 'API is configured and enabled',
unconfigured_desc: '需要配置 API Key', unconfigured_desc: 'Need to configure API Key',
configured_disabled_desc: 'API 已配置但未启用', configured_disabled_desc: 'API is configured but not enabled',
error_desc: 'API 已配置但链接异常', error_desc: 'API is configured but connection error',
serviceEndpoint: 'Service Endpoint URL', serviceEndpoint: 'Service Endpoint URL',
serviceEndpointPlaceholder: 'URL of the service endpoint', serviceEndpointPlaceholder: 'URL of the service endpoint',
@@ -1537,10 +1558,10 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re
parallel: 'Parallel Execution', parallel: 'Parallel Execution',
'var-aggregator': 'Variable Aggregator', 'var-aggregator': 'Variable Aggregator',
externalInteraction: 'External Interaction', externalInteraction: 'External Interaction',
http_request: 'HTTP Request', "http-request": 'HTTP Request',
tools: 'Tools', tools: 'Tools',
code_execution: 'Code Execution', code_execution: 'Code Execution',
template_rendering: 'Template Rendering', "jinja-render": 'Template Rendering',
cognitiveUpgrading: 'Cognitive Upgrading (Innovation)', cognitiveUpgrading: 'Cognitive Upgrading (Innovation)',
task_planning: 'Task Planning', task_planning: 'Task Planning',
reasoning_control: 'Reasoning Control', reasoning_control: 'Reasoning Control',

View File

@@ -511,7 +511,7 @@ export const zh = {
master: '主管模式', master: '主管模式',
master_agent: '主管模式', master_agent: '主管模式',
masterDesc: '由主 Agent 统一调度和管理,子 Agent 按照主管分配的任务执行,适合需要集中控制的场景。', master_agentDesc: '由主 Agent 统一调度和管理,子 Agent 按照主管分配的任务执行,适合需要集中控制的场景。',
handoffs: '协作模式', handoffs: '协作模式',
handoffsDesc: '多个 Agent 平等协作,根据任务需求自主协调配合,适合需要灵活互动的复杂场景。', handoffsDesc: '多个 Agent 平等协作,根据任务需求自主协调配合,适合需要灵活互动的复杂场景。',
masterConfig: '主管配置', masterConfig: '主管配置',
@@ -1091,6 +1091,14 @@ export const zh = {
quicklyForget: '快速遗忘', quicklyForget: '快速遗忘',
slowForgetting: '缓慢遗忘', slowForgetting: '缓慢遗忘',
currentConfig: '当前配置', currentConfig: '当前配置',
decay_constant: '衰减常数',
max_history_length: '访问历史最大长度',
forgetting_threshold: '遗忘阈值',
min_days_since_access: '最小未访问天数',
enable_llm_summary: '是否使用 LLM 生成摘要',
max_merge_batch_size: '单次最大融合节点对数',
forgetting_interval_hours: '遗忘周期间隔'
}, },
userMemory: { userMemory: {
userMemory: '用户记忆', userMemory: '用户记忆',
@@ -1651,10 +1659,10 @@ export const zh = {
parallel: '并行执行', parallel: '并行执行',
'var-aggregator': '变量聚合器', 'var-aggregator': '变量聚合器',
externalInteraction: '外部交互', externalInteraction: '外部交互',
http_request: 'HTTP请求', "http-request": 'HTTP请求',
tools: '工具 (Tools)', tools: '工具 (Tools)',
code_execution: '代码执行', code_execution: '代码执行',
template_rendering: '模板渲染', "jinja-render": '模板渲染',
cognitiveUpgrading: '认知升级(创新)', cognitiveUpgrading: '认知升级(创新)',
task_planning: '任务规划', task_planning: '任务规划',
reasoning_control: '推理控制', reasoning_control: '推理控制',
@@ -1756,7 +1764,37 @@ export const zh = {
"gt": '>', "gt": '>',
"ge": '>=', "ge": '>=',
else_desc: '用于定义当 if 条件不满足时应执行的逻辑。' else_desc: '用于定义当 if 条件不满足时应执行的逻辑。'
} },
'http-request': {
auth: '鉴权',
authType: '鉴权类型',
apiKey: 'API Key',
basic: '基础',
bearer: 'Bearer',
custom: '自定义',
header: 'Header',
api_key: 'API Key',
timeouts: '超时设置',
"connect_timeout": '连接超时(秒)',
"read_timeout": '读取超时(秒)',
"write_timeout": '写入超时(秒)',
retry: '失败时重试',
error_handle: '异常处理',
verify_ssl: '验证 SSL 证书',
none: '无',
default: '默认值',
branch: '异常分支',
status_code: '状态码',
max_attempts: '最大重试次数',
retry_interval: '重试间隔',
},
'jinja-render': {
template: '代码',
mapping: '输入变量'
},
name: '键',
type: '类型',
value: '值',
}, },
clear: '清空', clear: '清空',

View File

@@ -17,7 +17,8 @@ import type {
KnowledgeConfig, KnowledgeConfig,
Variable, Variable,
MemoryConfig, MemoryConfig,
AiPromptModalRef AiPromptModalRef,
Source
} from './types' } from './types'
import type { Model } from '@/views/ModelManagement/types' import type { Model } from '@/views/ModelManagement/types'
import { getModelList } from '@/api/models'; import { getModelList } from '@/api/models';
@@ -200,7 +201,7 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
}) })
} }
const refresh = (vo: ModelConfig, type: 'model' | 'chat') => { const refresh = (vo: ModelConfig, type: Source) => {
if (type === 'model') { if (type === 'model') {
const { default_model_config_id, ...rest } = vo const { default_model_config_id, ...rest } = vo
form.setFieldsValue({ form.setFieldsValue({
@@ -445,7 +446,6 @@ const Agent = forwardRef<AgentRef>((_props, ref) => {
<ModelConfigModal <ModelConfigModal
modelList={modelList} modelList={modelList}
data={formData as Config} data={formData as Config}
chatList={chatList}
ref={modelConfigModalRef} ref={modelConfigModalRef}
refresh={refresh} refresh={refresh}
/> />

View File

@@ -77,6 +77,7 @@ const Api: FC<{ application: Application | null }> = ({ application }) => {
title: t('common.confirmDeleteDesc', { name: vo.name }), title: t('common.confirmDeleteDesc', { name: vo.name }),
content: t('application.apiKeyDeleteContent'), content: t('application.apiKeyDeleteContent'),
okText: t('common.delete'), okText: t('common.delete'),
cancelText: t('common.cancel'),
okType: 'danger', okType: 'danger',
onOk: () => { onOk: () => {
deleteApiKey(vo.id) deleteApiKey(vo.id)

View File

@@ -1,29 +1,31 @@
import { type FC, useEffect, useState, useRef, forwardRef, useImperativeHandle, type Key } from 'react' import { useEffect, useState, useRef, forwardRef, useImperativeHandle } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import Card from './components/Card' import Card from './components/Card'
import { Form, Space, Row, Col, Button, Flex, App } from 'antd' import { Form, Space, Row, Col, Button, Flex, App, Select } from 'antd'
import type { DefaultOptionType } from 'antd/es/select'
import Tag, { type TagProps } from './components/Tag' import Tag, { type TagProps } from './components/Tag'
import CustomSelect from '@/components/CustomSelect'; import CustomSelect from '@/components/CustomSelect';
import { getApplicationListUrl, getMultiAgentConfig, saveMultiAgentConfig } from '@/api/application'; import { getMultiAgentConfig, saveMultiAgentConfig } from '@/api/application';
import type { import type {
Config, Config,
SubAgentModalRef, SubAgentModalRef,
ChatData, ChatData,
SubAgentItem, SubAgentItem,
ClusterRef ClusterRef,
ModelConfigModalRef
} from './types' } from './types'
import Chat from './components/Chat' import Chat from './components/Chat'
import RbCard from '@/components/RbCard/Card' import RbCard from '@/components/RbCard/Card'
import SubAgentModal from './components/SubAgentModal' import SubAgentModal from './components/SubAgentModal'
import Empty from '@/components/Empty' import Empty from '@/components/Empty'
import type { Application } from '@/views/ApplicationManagement/types' import RadioGroupCard from '@/components/RadioGroupCard'
import { getModelListUrl } from '@/api/models'
import ModelConfigModal from './components/ModelConfigModal'
const tagColors = ['processing', 'warning', 'default'] const tagColors = ['processing', 'warning', 'default']
const MAX_LENGTH = 5; const MAX_LENGTH = 5;
const Cluster = forwardRef<ClusterRef, { application: Application }>(({application}, ref) => { const Cluster = forwardRef<ClusterRef>((_props, ref) => {
const { t } = useTranslation() const { t } = useTranslation()
const { message } = App.useApp() const { message } = App.useApp()
const [form] = Form.useForm() const [form] = Form.useForm()
@@ -39,7 +41,15 @@ const Cluster = forwardRef<ClusterRef, { application: Application }>(({applicati
]) ])
const handleSave = (flag = true) => { const handleSave = (flag = true) => {
if (!data) return Promise.resolve()
if (!values.default_model_config_id) {
message.warning(t('common.selectPlaceholder', { title: t('application.model') }))
return Promise.resolve()
}
const params = { const params = {
id: data.id,
app_id: data.app_id,
...values, ...values,
sub_agents: (subAgents || []).map(item => ({ sub_agents: (subAgents || []).map(item => ({
...item, ...item,
@@ -47,6 +57,8 @@ const Cluster = forwardRef<ClusterRef, { application: Application }>(({applicati
})) }))
} }
console.log('params', params)
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
form.validateFields().then(() => { form.validateFields().then(() => {
saveMultiAgentConfig(id as string, params) saveMultiAgentConfig(id as string, params)
@@ -60,21 +72,14 @@ const Cluster = forwardRef<ClusterRef, { application: Application }>(({applicati
reject(error) reject(error)
}) })
}) })
.catch(error => { .catch(error => {
reject(error) reject(error)
}) })
}) })
} }
useEffect(() => { useEffect(() => {
getData() getData()
}, [id]) }, [id])
useEffect(() => {
if (application) {
form.setFieldsValue({
name: application.name,
})
}
}, [application])
const getData = () => { const getData = () => {
if (!id) { if (!id) {
@@ -93,7 +98,6 @@ const Cluster = forwardRef<ClusterRef, { application: Application }>(({applicati
subAgentModalRef.current?.handleOpen(agent) subAgentModalRef.current?.handleOpen(agent)
} }
const refreshSubAgents = (agent: SubAgentItem) => { const refreshSubAgents = (agent: SubAgentItem) => {
// setSubAgents(subAgents)
const index = subAgents.findIndex(item => item.agent_id === agent.agent_id) const index = subAgents.findIndex(item => item.agent_id === agent.agent_id)
const newSubAgents = [...subAgents] const newSubAgents = [...subAgents]
if (index === -1) { if (index === -1) {
@@ -110,57 +114,49 @@ const Cluster = forwardRef<ClusterRef, { application: Application }>(({applicati
const handleDeleteSubAgent = (agent: SubAgentItem) => { const handleDeleteSubAgent = (agent: SubAgentItem) => {
setSubAgents(prev => prev.filter(item => item.agent_id !== agent.agent_id)) setSubAgents(prev => prev.filter(item => item.agent_id !== agent.agent_id))
} }
const handleChange = (value: Key, option?: DefaultOptionType | DefaultOptionType[] | undefined) => {
if (option && !Array.isArray(option)) {
form.setFieldsValue({ master_agent_name: option.children })
}
}
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
handleSave handleSave
})) }))
const modelConfigModalRef = useRef<ModelConfigModalRef>(null)
const handleEditModelConfig = () => {
modelConfigModalRef.current?.handleOpen('multi_agent', values.model_parameters)
}
const handleSaveModelConfig = (values: Config['model_parameters']) => {
form.setFieldsValue({
model_parameters: values
})
}
return ( return (
<Row className="rb:h-[calc(100vh-64px)]"> <Row className="rb:h-[calc(100vh-64px)]">
<Col span={12} className="rb:h-full rb:overflow-x-auto rb:border-r rb:border-[#DFE4ED] rb:p-[20px_16px_24px_16px]"> <Col span={12} className="rb:h-full rb:overflow-x-auto rb:border-r rb:border-[#DFE4ED] rb:p-[20px_16px_24px_16px]">
<div className="rb:flex rb:items-center rb:justify-end rb:mb-[20px]"> <div className="rb:flex rb:items-center rb:justify-end rb:mb-5">
<Button type="primary" onClick={() => handleSave()}> <Button type="primary" onClick={() => handleSave()}>
{t('common.save')} {t('common.save')}
</Button> </Button>
</div> </div>
<Form form={form} layout="vertical"> <Form form={form} layout="vertical">
<Space size={20} direction="vertical" style={{width: '100%'}}> <Space size={20} direction="vertical" style={{width: '100%'}}>
<Card title={t('application.supervisorAgent')}> <Card title={t('application.handoffs')}>
<Row gutter={18}> <Form.Item
<Col span={24}> name={['execution_config', 'routing_mode']}
<Form.Item noStyle
name="master_agent_id" >
label={ <RadioGroupCard
<div className="rb:font-medium"> options={['master_agent', 'handoffs'].map((type) => ({
{t('application.agentName')} value: type,
</div> label: t(`application.${type}`),
} labelDesc: t(`application.${type}Desc`),
className="rb:mb-[20px]!" }))}
rules={[{ required: true, message: t('common.pleaseSelect') }]} allowClear={false}
> />
<CustomSelect </Form.Item>
url={getApplicationListUrl}
params={{ pagesize: 100, status: 'active', type: 'agent' }}
valueKey="id"
labelKey="name"
hasAll={false}
optionFilterProp="search"
showSearch={true}
onChange={handleChange}
/>
</Form.Item>
<Form.Item name="master_agent_name" hidden />
</Col>
</Row>
</Card> </Card>
<Card title={t('application.subAgentsManagement')}> <Card title={t('application.subAgentsManagement')}>
<Flex align="center" justify="space-between"> <Flex align="center" justify="space-between">
<div className="rb:font-regular rb:text-[#5B6167] rb:leading-[20px]">{t('application.added')}: {subAgents.length}/{MAX_LENGTH}</div> <div className="rb:font-regular rb:text-[#5B6167] rb:leading-5">{t('application.added')}: {subAgents.length}/{MAX_LENGTH}</div>
<Button size="small" disabled={subAgents.length >= MAX_LENGTH} onClick={() => handleSubAgentModal()}>{t('application.addSubAgent')}</Button> <Button size="small" disabled={subAgents.length >= MAX_LENGTH} onClick={() => handleSubAgentModal()}>{t('application.addSubAgent')}</Button>
</Flex> </Flex>
@@ -168,32 +164,81 @@ const Cluster = forwardRef<ClusterRef, { application: Application }>(({applicati
? <Empty size={88} /> ? <Empty size={88} />
: subAgents.map((agent, index) => ( : subAgents.map((agent, index) => (
<Flex key={index} align="center" justify="space-between" <Flex key={index} align="center" justify="space-between"
className="rb:mt-[16px]! rb:w-full! rb:border rb:border-[#DFE4ED] rb:rounded-[8px] rb:p-[20px_31px_20px_20px]!" className="rb:mt-4! rb:w-full! rb:border rb:border-[#DFE4ED] rb:rounded-lg rb:p-[20px_31px_20px_20px]!"
> >
<Flex className="rb:w-[calc(100%-80px)]!"> <Flex className="rb:w-[calc(100%-80px)]!">
<div className="rb:w-[48px] rb:h-[48px] rb:rounded-[8px] rb:mr-[13px] rb:bg-[#155eef] rb:flex rb:items-center rb:justify-center rb:text-[28px] rb:text-[#ffffff]"> <div className="rb:w-12 rb:h-12 rb:rounded-lg rb:mr-3.25 rb:bg-[#155eef] rb:flex rb:items-center rb:justify-center rb:text-[28px] rb:text-[#ffffff]">
{agent.name?.[0]} {agent.name?.[0]}
</div> </div>
<div className="rb:flex rb:flex-col rb:justify-center rb:max-w-[calc(100%-60px)]"> <div className="rb:flex rb:flex-col rb:justify-center rb:max-w-[calc(100%-60px)]">
{agent.name} {agent.name}
{agent.role && <div className="rb:font-regular rb:leading-[20px] rb:text-[#5B6167] rb:mt-[6px]">{agent.role || '-'}</div>} {agent.role && <div className="rb:font-regular rb:leading-5 rb:text-[#5B6167] rb:mt-1.5">{agent.role || '-'}</div>}
{agent.capabilities && <Flex wrap gap={8} className="rb:mt-[16px]">{agent.capabilities.map((tag, tagIndex) => <Tag key={tagIndex} color={tagColors[tagIndex % tagColors.length] as TagProps['color']}>{tag}</Tag>)}</Flex>} {agent.capabilities && <Flex wrap gap={8} className="rb:mt-4">{agent.capabilities.map((tag, tagIndex) => <Tag key={tagIndex} color={tagColors[tagIndex % tagColors.length] as TagProps['color']}>{tag}</Tag>)}</Flex>}
</div> </div>
</Flex> </Flex>
<Space> <Space>
<div <div
className="rb:w-[32px] rb:h-[32px] rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/editBorder.svg')] rb:hover:bg-[url('@/assets/images/editBg.svg')]" className="rb:w-8 rb:h-8 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/editBorder.svg')] rb:hover:bg-[url('@/assets/images/editBg.svg')]"
onClick={() => handleSubAgentModal(agent)} onClick={() => handleSubAgentModal(agent)}
></div> ></div>
<div <div
className="rb:w-[32px] rb:h-[32px] rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/deleteBorder.svg')] rb:hover:bg-[url('@/assets/images/deleteBg.svg')]" className="rb:w-8 rb:h-8 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/deleteBorder.svg')] rb:hover:bg-[url('@/assets/images/deleteBg.svg')]"
onClick={() => handleDeleteSubAgent(agent)} onClick={() => handleDeleteSubAgent(agent)}
></div> ></div>
</Space> </Space>
</Flex> </Flex>
))} ))}
</Card> </Card>
<Card title={t('application.masterConfig')}>
<Form.Item
label={t('application.model')}
required={true}
>
<Row gutter={16}>
<Col span={16}>
<Form.Item name="default_model_config_id" noStyle>
<CustomSelect
url={getModelListUrl}
params={{ type: 'llm,chat', pagesize: 100 }}
valueKey="id"
labelKey="name"
hasAll={false}
style={{ width: '100%' }}
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="model_parameters" noStyle>
<Button onClick={handleEditModelConfig}>{t('application.modelConfig')}</Button>
</Form.Item>
</Col>
</Row>
</Form.Item>
<Form.Item
name="orchestration_mode"
label={t('application.orchestrationMode')}
>
<Select
options={['conditional', 'sequential', 'parallel'].map((type) => ({
value: type,
label: t(`application.${type}`),
}))}
/>
</Form.Item>
<Form.Item
name="aggregation_strategy"
label={t('application.aggregationStrategy')}
>
<Select
options={['merge', 'vote', 'priority'].map((type) => ({
value: type,
label: t(`application.${type}`),
}))}
/>
</Form.Item>
</Card>
</Space> </Space>
</Form> </Form>
</Col> </Col>
@@ -213,6 +258,11 @@ const Cluster = forwardRef<ClusterRef, { application: Application }>(({applicati
ref={subAgentModalRef} ref={subAgentModalRef}
refresh={refreshSubAgents} refresh={refreshSubAgents}
/> />
<ModelConfigModal
data={values as Config}
ref={modelConfigModalRef}
refresh={handleSaveModelConfig}
/>
</Row> </Row>
) )
}) })

View File

@@ -16,7 +16,7 @@ interface ChatProps {
chatList: ChatData[]; chatList: ChatData[];
data: Config; data: Config;
updateChatList: React.Dispatch<React.SetStateAction<ChatData[]>>; updateChatList: React.Dispatch<React.SetStateAction<ChatData[]>>;
handleSave: (flag?: boolean) => Promise<any>; handleSave: (flag?: boolean) => Promise<unknown>;
source?: 'multi_agent' | 'agent'; source?: 'multi_agent' | 'agent';
} }
const Chat: FC<ChatProps> = ({ chatList, data, updateChatList, handleSave, source = 'agent' }) => { const Chat: FC<ChatProps> = ({ chatList, data, updateChatList, handleSave, source = 'agent' }) => {
@@ -74,7 +74,7 @@ const Chat: FC<ChatProps> = ({ chatList, data, updateChatList, handleSave, sourc
const curModelChat = modelChatList[targetIndex] const curModelChat = modelChatList[targetIndex]
const curChatMsgList = curModelChat.list || [] const curChatMsgList = curModelChat.list || []
const lastMsg = curChatMsgList[curChatMsgList.length - 1] const lastMsg = curChatMsgList[curChatMsgList.length - 1]
if (lastMsg.role === 'assistant') { if (lastMsg && lastMsg.role === 'assistant') {
modelChatList[targetIndex] = { modelChatList[targetIndex] = {
...modelChatList[targetIndex], ...modelChatList[targetIndex],
conversation_id: conversation_id, conversation_id: conversation_id,
@@ -139,7 +139,7 @@ const Chat: FC<ChatProps> = ({ chatList, data, updateChatList, handleSave, sourc
data.map(item => { data.map(item => {
const { model_config_id, conversation_id, content, message_length } = item.data as { model_config_id: string; conversation_id: string; content: string; message_length: number }; const { model_config_id, conversation_id, content, message_length } = item.data as { model_config_id: string; conversation_id: string; content: string; message_length: number };
switch(item.event) { switch (item.event) {
case 'model_message': case 'model_message':
updateAssistantMessage(content, model_config_id, conversation_id) updateAssistantMessage(content, model_config_id, conversation_id)
break; break;

View File

@@ -93,18 +93,15 @@ export interface Config extends MultiAgentConfig {
export interface MultiAgentConfig { export interface MultiAgentConfig {
id: string; id: string;
app_id: string; app_id: string;
// system_prompt: string; default_model_config_id?: string;
// default_model_config_id?: string; model_parameters: ModelConfig;
// model_parameters: ModelConfig; orchestration_mode: 'conditional' | 'sequential' | 'parallel';
// knowledge_retrieval: KnowledgeConfig | null;
// memory?: MemoryConfig;
// variables: Variable[];
// tools: Record<string, string>;
// is_active: boolean;
// created_at: number;
// updated_at: number;
master_agent_id?: string;
sub_agents?: SubAgentItem[]; sub_agents?: SubAgentItem[];
routing_rules: null;
execution_config: {
routing_mode: 'master' | 'handoffs'
};
aggregation_strategy: 'merge' | 'vote' | 'priority'
} }
// 创建表单数据类型 // 创建表单数据类型
@@ -116,21 +113,22 @@ export interface ApplicationModalData {
// 定义组件暴露的方法接口 // 定义组件暴露的方法接口
export interface AgentRef { export interface AgentRef {
handleSave: (flag?: boolean) => Promise<any>; handleSave: (flag?: boolean) => Promise<unknown>;
} }
export interface ClusterRef { export interface ClusterRef {
handleSave: (flag?: boolean) => Promise<any>; handleSave: (flag?: boolean) => Promise<unknown>;
} }
export interface WorkflowRef { export interface WorkflowRef {
handleSave: (flag?: boolean) => Promise<any>; handleSave: (flag?: boolean) => Promise<unknown>;
handleRun: () => void; handleRun: () => void;
graphRef: GraphRef graphRef: GraphRef
} }
export interface ApplicationModalRef { export interface ApplicationModalRef {
handleOpen: (application?: Config) => void; handleOpen: (application?: Config) => void;
} }
export type Source = 'chat' | 'model' | 'multi_agent'
export interface ModelConfigModalRef { export interface ModelConfigModalRef {
handleOpen: (source: 'chat' | 'model') => void; handleOpen: (source: Source, model?: any) => void;
} }
export interface ModelConfigModalData { export interface ModelConfigModalData {
model: string; model: string;