diff --git a/frontend-web/src/roundtable-planning/components/BusinessChainPicker.tsx b/frontend-web/src/roundtable-planning/components/BusinessChainPicker.tsx index 154c088c..136cd561 100644 --- a/frontend-web/src/roundtable-planning/components/BusinessChainPicker.tsx +++ b/frontend-web/src/roundtable-planning/components/BusinessChainPicker.tsx @@ -13,7 +13,7 @@ * * 详见 `docs/multi-agent-business-chain-dev.md` §6.2 / §7 阶段 3。 */ -import { Fragment, useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useState, type ReactNode } from "react"; import { ArrowRightIcon, CheckIcon, @@ -313,27 +313,35 @@ function ChainCard({ {/* 智能体名 tag(按顺序,← 箭头连接) */}
- {chain.seats.map((seat, i) => { + {chain.seats.flatMap((seat, i) => { const alive = isExisting(seat.agent_id); const label = nameById.get(seat.agent_id) ?? seat.name ?? seat.agent_id; - return ( - - {i > 0 && ( - + // 不用 :dev 期 tagger 会往 Fragment 注入 data-lov-id 触发 React 警告, + // 这里改成带 key 的扁平数组(箭头 + tag),注入落到真实元素上即可。 + const nodes: ReactNode[] = []; + if (i > 0) { + nodes.push( + , + ); + } + nodes.push( + - {label} - - + title={alive ? undefined : "该智能体已不存在"} + > + {label} + , ); + return nodes; })}
diff --git a/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts b/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts index 7decbaf5..f27035df 100644 --- a/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts +++ b/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts @@ -591,7 +591,18 @@ export function useStep2Orchestration( * auto=false(用户点击步骤 / 文件卡)始终强制打开。 */ const openSeatVirtualArtifact = useCallback( - (seatThreadId: string, virtualUrl: string, auto: boolean) => { + ( + seatThreadId: string, + virtualUrl: string, + auto: boolean, + opts?: { manual?: boolean }, + ) => { + // manual=true → 视为「用户手动接管」,会把全局 autoSelect 置 false(尊重用户后续不再 + // 自动选/自动开)。默认沿用旧语义:auto=false 即手动点击(文件卡 / 步骤)。 + // 但**系统程序化打开**(如沙箱跟随 openSeatLatestArtifact)必须传 manual:false —— + // 否则会误关 autoSelect,毒化随后实时 write_file 的 auto=true 自动打开,表现为 + // 「单个智能体发言时沙箱不自动打开、只能手动开」(763eb4d 沙箱跟随引入的回归)。 + const manual = opts?.manual ?? !auto; if (auto) { if (hasAutoOpenedRef.current.has(virtualUrl)) return; const flags = autoOpenFlagsRef.current; @@ -618,7 +629,8 @@ export function useStep2Orchestration( } setActiveArtifactThreadId(seatThreadId); const open = () => { - selectArtifact(virtualUrl, auto); + // select 的第 2 参 = autoSelect:true 表示「自动选,不毒化」;只有真正手动接管才传 false。 + selectArtifact(virtualUrl, !manual); setArtifactsOpen(true); }; if (auto) { @@ -658,7 +670,9 @@ export function useStep2Orchestration( : ""; if (!path) continue; const virtualUrl = buildWriteFileVirtualUrl(path, stub.id, tc.id); - openSeatVirtualArtifact(seatThreadId, virtualUrl, false); + // manual:false —— 沙箱跟随是系统行为,强制打开但**不**关闭 autoSelect(否则毒化 + // 后续实时自动打开,见 openSeatVirtualArtifact 注释)。 + openSeatVirtualArtifact(seatThreadId, virtualUrl, false, { manual: false }); return true; } return false; diff --git a/offline-backend-20260512/.env b/offline-backend-20260512/.env index 715e331f..91938f1e 100644 --- a/offline-backend-20260512/.env +++ b/offline-backend-20260512/.env @@ -17,7 +17,7 @@ SERPER_API_KEY=your-serper-api-key # AUTH_JWT_SECRET must stay stable across restarts, or existing logins expire. # GATEWAY_CORS_ORIGINS must include the exact frontend origins, separated by commas. AUTH_JWT_SECRET=i3_BiBK44sYHiFIkChhDs46y57ZewJKO3diQDw01anI -GATEWAY_CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173,http://localhost:5174,http://127.0.0.1:5174 +GATEWAY_CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173,http://localhost:5174,http://127.0.0.1:5174,http://localhost:4200 GATEWAY_CORS_ALLOW_ALL=0 GATEWAY_ENABLE_DOCS=true GATEWAY_WORKERS=2 diff --git a/offline-backend-20260512/backend/config.yaml b/offline-backend-20260512/backend/config.yaml index d09cc045..152ebfb2 100644 --- a/offline-backend-20260512/backend/config.yaml +++ b/offline-backend-20260512/backend/config.yaml @@ -14,7 +14,7 @@ models: display_name: DeepSeek Chat use: langchain_openai:ChatOpenAI model: deepseek-chat - api_key: sk-1520028668cb4cc388ed8315ff1e856e + api_key: sk-e1c22b7931dc446f8b67e57878edd105 base_url: https://api.deepseek.com request_timeout: 600.0 max_retries: 2