From c36563f96887cd1c1daad7025c63d10e2ef96b8e Mon Sep 17 00:00:00 2001 From: ViperEkura <3081035982@qq.com> Date: Tue, 28 Apr 2026 23:19:47 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E7=9B=91=E7=9D=A3=E5=85=B3=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/SupervisionGraphEditor.vue | 1159 +++++++++++++++++ dashboard/src/views/ChatRoomView.vue | 474 ++++++- luxx/routes/chat_rooms.py | 18 +- 3 files changed, 1647 insertions(+), 4 deletions(-) create mode 100644 dashboard/src/components/SupervisionGraphEditor.vue diff --git a/dashboard/src/components/SupervisionGraphEditor.vue b/dashboard/src/components/SupervisionGraphEditor.vue new file mode 100644 index 0000000..e30bfa8 --- /dev/null +++ b/dashboard/src/components/SupervisionGraphEditor.vue @@ -0,0 +1,1159 @@ + + + + + diff --git a/dashboard/src/views/ChatRoomView.vue b/dashboard/src/views/ChatRoomView.vue index d100a0e..f3f52bb 100644 --- a/dashboard/src/views/ChatRoomView.vue +++ b/dashboard/src/views/ChatRoomView.vue @@ -5,6 +5,7 @@ import { parallelStreamManager } from '../utils/parallelStreamManager.js' import { useParallelStreamStore } from '../utils/parallelStreamStore.js' import MessageBubble from '../components/MessageBubble.vue' import ParallelMessages from '../components/ParallelMessages.vue' +import SupervisionGraphEditor from '../components/SupervisionGraphEditor.vue' const store = useParallelStreamStore() @@ -52,6 +53,133 @@ const creating = ref(false) const newRoom = ref({ title: '', task: '', max_rounds: 5, agent_ids: [], execution_mode: 'sequential' }) const showAddToRoom = ref(false) +// ============ Wizard state (Supervision Graph) ============ +const showCreateWizard = ref(false) +const wizardStep = ref(1) +const wizardData = ref({ + title: '', + task: '', + max_rounds: 5, + execution_mode: 'sequential', + agent_ids: [], + agent_roles: {}, + supervision_edges: [] +}) +const wizardRef = ref(null) // 用于参考 SuperGraphEditor 组件 + +// Wizard navigation +function openWizard() { + wizardStep.value = 1 + wizardData.value = { + title: '', + task: '', + max_rounds: 5, + execution_mode: 'sequential', + agent_ids: [], + agent_roles: {}, + supervision_edges: [] + } + showCreateWizard.value = true +} + +function closeWizard() { + showCreateWizard.value = false + wizardStep.value = 1 +} + +function nextWizardStep() { + if (wizardStep.value < 4) wizardStep.value++ +} + +function prevWizardStep() { + if (wizardStep.value > 1) wizardStep.value-- +} + +function selectWizardTemplate(templateId) { + // 根据任务模板填充默认的 task 描述 + const templates = { + custom: '请描述需要 Agent 团队完成的任务...', + code_review: '请对以下代码进行全面的审查和改进:\n\n```\n\n```', + architecture: '请设计一个系统架构方案,涵盖:\n1. 系统架构概览\n2. 核心模块设计\n3. 数据流设计\n4. 技术选型', + debugging: '请协助排查以下问题:\n\n问题描述:\n\n复现步骤:\n\n错误日志:' + } + if (templates[templateId] && !wizardData.value.task) { + wizardData.value.task = templates[templateId] + } +} + +function toggleWizardAgent(agentId) { + const idx = wizardData.value.agent_ids.indexOf(agentId) + if (idx >= 0) { + wizardData.value.agent_ids.splice(idx, 1) + delete wizardData.value.agent_roles[agentId] + } else { + wizardData.value.agent_ids.push(agentId) + wizardData.value.agent_roles[agentId] = 'producer' + } +} + +function onSupervisionChange(config) { + if (config) { + wizardData.value.agent_roles = config.roles || {} + wizardData.value.supervision_edges = config.edges || [] + } +} + +async function createRoomFromWizard() { + const data = wizardData.value + if (!data.title || !data.task || data.agent_ids.length === 0) return + + creating.value = true + try { + // 获取 SupervisionGraphEditor 的完整配置 + let supervisionConfig = null + if (wizardRef.value && data.execution_mode === 'review_loop') { + supervisionConfig = wizardRef.value.getSupervisionConfig() + } + + // 构建 agent 列表 + const agents = data.agent_ids + .map(id => agentPool.value.find(a => a.id === id)) + .filter(Boolean) + .map((a, idx) => { + const base = { agent_id: a.id } + if (data.execution_mode === 'review_loop') { + // 添加监督角色和边配置 + const role = data.agent_roles[a.id] || 'producer' + const edgeConfig = supervisionConfig?.edges?.filter(e => e.source === a.id || e.target === a.id) || [] + return { + ...base, + agent_type: role, + reviews_for: JSON.stringify( + edgeConfig.filter(e => e.source === a.id).map(e => e.target) + ), + reviewed_by: JSON.stringify( + edgeConfig.filter(e => e.target === a.id).map(e => e.source) + ) + } + } + return base + }) + + const res = await chatRoomsAPI.create({ + title: data.title, + task: data.task, + max_rounds: data.max_rounds, + execution_mode: data.execution_mode, + agents + }) + closeWizard() + await loadRooms() + const created = res.data + if (created?.id) selectRoom(created.id) + } catch (e) { + console.error('Failed to create room:', e) + } finally { + creating.value = false + } +} + // ============ Selected room state ============ const selectedId = ref(null) const room = ref(null) @@ -581,6 +709,33 @@ function randomColor() { return colors[Math.floor(Math.random() * colors.length)] } +// ============ Wizard helpers ============ +function getAgentColor(id) { + const agent = agentPool.value.find(a => a.id === id) + return agent?.color || '#3b82f6' +} + +function getAgentName(id) { + const agent = agentPool.value.find(a => a.id === id) + return agent?.name || `Agent ${id}` +} + +function getSelectedAgents() { + return wizardData.value.agent_ids + .map(id => agentPool.value.find(a => a.id === id)) + .filter(Boolean) +} + +function getRoleLabelText(role) { + const labels = { + producer: '🎨 Producer - 方案提出者', + reviewer: '🔍 Reviewer - 审查员', + executor: '⚙️ Executor - 执行者', + observer: '👁️ Observer - 观察员' + } + return labels[role] || role +} + watch(messages, () => { nextTick(scrollToBottom) }, { deep: true }) // 启动聊天室时强制滚动 @@ -639,7 +794,7 @@ onUnmounted(() => { @@ -755,6 +911,7 @@ onUnmounted(() => { > + @@ -886,6 +1043,7 @@ onUnmounted(() => { @@ -966,6 +1124,258 @@ onUnmounted(() => { + + +
+
+ +
+

{{ wizardData.execution_mode === 'review_loop' ? '🔄 创建监督型聊天室' : '🤖 创建聊天室' }}

+ +
+ + +
+
+ 1 + 基本信息 +
+
+
+ 2 + 选择 Agent +
+
+
+ 3 + {{ wizardData.execution_mode === 'review_loop' ? '监督关系' : '确认' }} +
+
+
+ 4 + 确认创建 +
+
+ + +
+
+
📋 基本设置
+
+
+
+
+ + +
+
+ + +
+
+ +
+
+ 🔍 + 代码审查 +
+
+ 🏗️ + 架构设计 +
+
+ 🐛 + 调试排查 +
+
+ 📝 + 自定义 +
+
+
+ + +
+
🤖 选择参与讨论的 Agent
+
+

暂无可用 Agent,请先在 Agent 池中创建

+ +
+
+
+ + {{ agent.name.charAt(0) }} +
+ {{ agent.name }} + {{ agent.role || '通用' }} +
+ {{ agent.model || 'default' }} +
+
+
+ 已选择 {{ wizardData.agent_ids.length }} 个 Agent +
+
请选择至少 1 个 Agent
+
+ + +
+ + +
+ + +
+
📋 确认配置
+
+
+

基本信息

+
标题: {{ wizardData.title }}
+
执行模式: {{ wizardData.execution_mode === 'review_loop' ? '🔄 监督循环' : wizardData.execution_mode === 'parallel' ? '⚡ 并行' : '📋 串行' }}
+
最大轮次: {{ wizardData.max_rounds }}
+
任务: {{ wizardData.task }}
+
+
+

Agent 列表

+
+
+ + {{ getAgentName(agentId).charAt(0) }} + +
+ {{ getAgentName(agentId) }} + + {{ getRoleLabelText(wizardData.agent_roles[agentId]) }} + +
+
+
+
+
+

监督关系 ({{ wizardData.supervision_edges.length }} 条)

+
+
+ {{ getAgentName(edge.source) }} + + {{ getAgentName(edge.target) }} + ★{{ edge.strictness }} + {{ edge.focus }} +
+
+
+
+
+
+ + + +
+
+ diff --git a/luxx/routes/chat_rooms.py b/luxx/routes/chat_rooms.py index 2d8c65b..f56bf6e 100644 --- a/luxx/routes/chat_rooms.py +++ b/luxx/routes/chat_rooms.py @@ -25,12 +25,19 @@ class AgentConfig(BaseModel): model: str = "" system_prompt: str = "You are a helpful AI assistant." color: str = "#2563eb" + # Supervision fields + agent_type: str = "producer" # producer | reviewer | executor | observer + reviews_for: Optional[str] = None # JSON: [agent_id_1, agent_id_2] + reviewed_by: Optional[str] = None # JSON: [agent_id_1, agent_id_2] + review_strictness: int = 3 + capability_tags: Optional[str] = None # JSON: ["security", "performance"] class ChatRoomCreate(BaseModel): title: str task: str max_rounds: int = 5 + execution_mode: str = "sequential" # sequential | parallel | review_loop agents: List[AgentConfig] = [] @@ -39,6 +46,7 @@ class ChatRoomUpdate(BaseModel): task: Optional[str] = None max_rounds: Optional[int] = None status: Optional[str] = None + execution_mode: Optional[str] = None class AgentCreate(BaseModel): @@ -93,7 +101,8 @@ def create_room( user_id=current_user.id, title=data.title, task=data.task, - max_rounds=data.max_rounds + max_rounds=data.max_rounds, + execution_mode=data.execution_mode ) db.add(room) db.flush() @@ -152,7 +161,12 @@ def create_room( model=model, system_prompt=system_prompt, color=color, - turn_order=i + turn_order=i, + agent_type=agent_cfg.agent_type, + reviews_for=agent_cfg.reviews_for, + reviewed_by=agent_cfg.reviewed_by, + review_strictness=agent_cfg.review_strictness, + capability_tags=agent_cfg.capability_tags ) db.add(agent)