diff --git a/frontend-web/src/components/workspace/agents/agent-card.tsx b/frontend-web/src/components/workspace/agents/agent-card.tsx index cfd7e8c2..c28771b0 100644 --- a/frontend-web/src/components/workspace/agents/agent-card.tsx +++ b/frontend-web/src/components/workspace/agents/agent-card.tsx @@ -229,6 +229,10 @@ export function AgentCard({ agent, layout = "card", onPublisherClick }: AgentCar ); const [editPublished, setEditPublished] = useState(agent.published); const [editIsPrivate, setEditIsPrivate] = useState(agent.is_private); + // 会商席位「技能识别强化」开关(弱模型补偿)。默认关。 + const [editSeatSkillDirective, setEditSeatSkillDirective] = useState( + agent.seat_skill_directive ?? false, + ); const [editSquareId, setEditSquareId] = useState(agent.square_id ?? ""); const [publishPickerOpen, setPublishPickerOpen] = useState(false); const { data: publishSquares } = usePublishSquares(); @@ -274,6 +278,7 @@ export function AgentCard({ agent, layout = "card", onPublisherClick }: AgentCar setEditSquareId(agent.square_id ?? ""); setSelectedSkills(agent.skills ?? []); setEditCommonQuestions(normalizeAgentQuestions(agent.common_questions)); + setEditSeatSkillDirective(agent.seat_skill_directive ?? false); }, [ agent.common_questions, agent.description, @@ -282,6 +287,7 @@ export function AgentCard({ agent, layout = "card", onPublisherClick }: AgentCar agent.published, agent.square_id, agent.skills, + agent.seat_skill_directive, editOpen, ]); @@ -295,6 +301,8 @@ export function AgentCard({ agent, layout = "card", onPublisherClick }: AgentCar if (agentDetail) { setEditSoul(agentDetail.soul ?? ""); setEditCommonQuestions(normalizeAgentQuestions(agentDetail.common_questions)); + // 列表响应不带 config 额外字段(seat_skill_directive 为 null),详情才有真值。 + setEditSeatSkillDirective(agentDetail.seat_skill_directive ?? false); } else { setEditSoul(agent.soul ?? ""); } @@ -386,6 +394,8 @@ export function AgentCard({ agent, layout = "card", onPublisherClick }: AgentCar request.skills = selectedSkills; if (JSON.stringify(nextQuestions) !== JSON.stringify(baselineQuestions)) request.common_questions = nextQuestions; + if (editSeatSkillDirective !== ((agentDetail?.seat_skill_directive ?? agent.seat_skill_directive) ?? false)) + request.seat_skill_directive = editSeatSkillDirective; if (Object.keys(request).length === 0) { setEditOpen(false); @@ -960,6 +970,19 @@ export function AgentCard({ agent, layout = "card", onPublisherClick }: AgentCar onChange={setEditCommonQuestions} /> +
+
+

会商技能识别强化

+

+ 作为会商席位时,把已配置技能(含 SKILL.md 路径与「先 read_file + 再用」硬指令)拼进任务,补偿弱模型不识别技能。也可在业务链条配置里打开(任一即生效)。 +

+
+ +

公开发布

diff --git a/frontend-web/src/components/workspace/agents/agent-detail-panel.tsx b/frontend-web/src/components/workspace/agents/agent-detail-panel.tsx index 9a40afc3..0d6bc0b1 100644 --- a/frontend-web/src/components/workspace/agents/agent-detail-panel.tsx +++ b/frontend-web/src/components/workspace/agents/agent-detail-panel.tsx @@ -76,6 +76,8 @@ interface AgentDraft { published: boolean; featured: boolean; templateName: string; + /** 会商席位「技能识别强化」开关。 */ + seatSkillDirective: boolean; } function draftFromAgent(agent: Agent): AgentDraft { @@ -88,6 +90,7 @@ function draftFromAgent(agent: Agent): AgentDraft { published: agent.published, featured: agent.featured_order != null, templateName: agent.template_name ?? "", + seatSkillDirective: agent.seat_skill_directive ?? false, }; } @@ -295,6 +298,8 @@ export function AgentDetailPanel({ if (draft.soul !== (agent.soul ?? "")) request.soul = draft.soul; if (draft.templateName.trim() !== (agent.template_name ?? "")) request.template_name = draft.templateName.trim(); + if (draft.seatSkillDirective !== (agent.seat_skill_directive ?? false)) + request.seat_skill_directive = draft.seatSkillDirective; if (nextPublished !== agent.published) request.published = nextPublished; if (JSON.stringify(draft.skills) !== JSON.stringify(agent.skills ?? [])) request.skills = draft.skills; @@ -561,6 +566,21 @@ export function AgentDetailPanel({ 配置后,对话生成的 Markdown 文件可一键发布到知识入库接口。

+
+
+

会商技能识别强化

+

+ 作为会商席位时,把已配置技能(含 SKILL.md 路径与「先 read_file + 再用」硬指令)拼进任务,补偿弱模型不识别技能。也可在业务链条配置中打开(任一即生效)。 +

+
+ + setDraft({ ...draft, seatSkillDirective: checked }) + } + /> +

公开发布

diff --git a/frontend-web/src/core/agents/types.ts b/frontend-web/src/core/agents/types.ts index 0af55b85..283993f8 100644 --- a/frontend-web/src/core/agents/types.ts +++ b/frontend-web/src/core/agents/types.ts @@ -58,6 +58,10 @@ export interface Agent { /** 入库模板名(外部知识入库接口的 templateName)。配置后该智能体会话中的 * Markdown 产物右上角出现"发布入库"按钮。空/缺省 = 不支持入库。 */ template_name?: string | null; + /** 会商席位「技能识别强化」开关。作为会商席位运行时,是否把本智能体配置的技能 + * (名称 + SKILL.md 路径 + 必须先 read_file 的硬指令) 拼进本轮任务以补偿弱模型。 + * 与业务链条同名开关取 OR。null/false = 关 (默认)。 */ + seat_skill_directive?: boolean | null; tags?: Tag[]; featured_order?: number | null; /** Whether the current user has favorited (收藏) this agent. */ @@ -91,6 +95,8 @@ export interface CreateAgentRequest { tool_groups?: string[] | null; common_questions?: AgentQuestion[] | null; template_name?: string | null; + /** 会商席位「技能识别强化」开关;缺省/false = 关。 */ + seat_skill_directive?: boolean | null; } export interface UpdateAgentRequest { @@ -106,4 +112,6 @@ export interface UpdateAgentRequest { common_questions?: AgentQuestion[] | null; /** 入库模板名;传空字符串表示清除。 */ template_name?: string | null; + /** 会商席位「技能识别强化」开关;缺省/false = 关。 */ + seat_skill_directive?: boolean | null; } diff --git a/frontend-web/src/pages/NewAgentPage.tsx b/frontend-web/src/pages/NewAgentPage.tsx index 4ab2564a..f3c165a3 100644 --- a/frontend-web/src/pages/NewAgentPage.tsx +++ b/frontend-web/src/pages/NewAgentPage.tsx @@ -83,6 +83,8 @@ export default function NewAgentPage() { const [modelInput, setModelInput] = useState(""); const [chatModelInput, setChatModelInput] = useState(""); const [templateNameInput, setTemplateNameInput] = useState(""); + // 会商席位「技能识别强化」开关(弱模型补偿)。默认关。 + const [seatSkillDirectiveInput, setSeatSkillDirectiveInput] = useState(false); const [formError, setFormError] = useState(""); const [agentId, setAgentId] = useState(""); const [agent, setAgent] = useState(null); @@ -230,6 +232,7 @@ export default function NewAgentPage() { skills: selectedSkills, model: modelOverride, template_name: templateNameInput.trim(), + seat_skill_directive: seatSkillDirectiveInput, }); setAgent(updated); return updated; @@ -251,6 +254,7 @@ export default function NewAgentPage() { skills: selectedSkills, model: modelOverride, template_name: templateNameInput.trim(), + seat_skill_directive: seatSkillDirectiveInput, }); setAgentId(created.id); setAgent(created); @@ -281,6 +285,7 @@ export default function NewAgentPage() { selectedSkills, soulInput, templateNameInput, + seatSkillDirectiveInput, t.agents.nameStepCheckError, t.agents.nameStepNetworkError, validateForm, diff --git a/frontend-web/src/roundtable-planning/api/multi-agent.ts b/frontend-web/src/roundtable-planning/api/multi-agent.ts index 316120fc..02c7fd99 100644 --- a/frontend-web/src/roundtable-planning/api/multi-agent.ts +++ b/frontend-web/src/roundtable-planning/api/multi-agent.ts @@ -234,6 +234,12 @@ export interface StreamMultiAgentRequest { reasoningEffort?: "minimal" | "low" | "medium" | "high"; /** 仅 special 用;ultra 档置真,给席位解锁 `task` 子代理工具。 */ subagentEnabled?: boolean; + /** + * 仅 special 用。会商席位「技能识别强化」开关(沿用所选业务链条配置)。置 true 时后端把该 + * 席位配置的技能(含 SKILL.md 路径 + 必须先 read_file 的硬指令)拼进本轮任务,补偿弱模型。 + * 与该席位 agent 自身 config.yaml 的同名开关取 OR。省略 = false(关)。 + */ + seatSkillDirective?: boolean; skillStopNames?: string[]; /** * 仅 leader 用。置 true 表示这是「派活后让总控判断继续/综合」的轮次:后端会把各已交付 @@ -485,6 +491,8 @@ export async function streamMultiAgent( thinking_enabled: req.thinkingEnabled, reasoning_effort: req.reasoningEffort, subagent_enabled: req.subagentEnabled, + // 仅 special 用;会商技能识别强化(沿用所选业务链条开关)。省略 → 后端按 false(关)处理。 + seat_skill_directive: req.seatSkillDirective ?? false, skill_stop_names: req.skillStopNames ?? [], // 仅 leader 用;综合轮让后端注入各席位完整交付正文。省略 → 后端按 false 处理。 synthesis_mode: req.synthesisMode ?? false, diff --git a/frontend-web/src/roundtable-planning/api/roundtable-jobs.ts b/frontend-web/src/roundtable-planning/api/roundtable-jobs.ts index bcf251cd..befe38e1 100644 --- a/frontend-web/src/roundtable-planning/api/roundtable-jobs.ts +++ b/frontend-web/src/roundtable-planning/api/roundtable-jobs.ts @@ -98,6 +98,9 @@ function toStartBody(p: StartJobPayload) { seedMessage: p.seedMessage, threadIds: p.threadIds ?? null, coordinatorName: p.coordinatorName ?? "roundtable-coordinator", + // 每席位技能识别强化映射 {agentId: bool}:沿用所选业务链条里各席位的开关;缺省 {}。 + // 后端 run_seat 按 agentId 查表,与各席位 agent 自身开关取 OR。 + seat_skill_directives: p.seatSkillDirectives ?? {}, ...(seat ? { thinking_enabled: seat.thinking_enabled, diff --git a/frontend-web/src/roundtable-planning/components/BusinessChainPicker.tsx b/frontend-web/src/roundtable-planning/components/BusinessChainPicker.tsx index 0254d886..9a1b5b36 100644 --- a/frontend-web/src/roundtable-planning/components/BusinessChainPicker.tsx +++ b/frontend-web/src/roundtable-planning/components/BusinessChainPicker.tsx @@ -150,18 +150,21 @@ export function BusinessChainPicker({ // 席位模型覆盖(链条配置):按 agent_id 取,空/缺省 = 跟随全局模型。 const modelById = new Map(selectedChain.seats.map((s) => [s.agent_id, s.model ?? null])); const modelOf = (id: string) => modelById.get(id) ?? null; + // 席位「会商技能识别强化」开关(链条配置):按 agent_id 取,缺省 = 关。 + const skillById = new Map(selectedChain.seats.map((s) => [s.agent_id, s.seat_skill_directive ?? false])); + const skillOf = (id: string) => skillById.get(id) ?? false; // 链条带分层、过滤存活后仍并行 → dag 编排(携带快速/沙箱子模式);否则退回线性 chain。 if (dagPlan) { // dag:席位顺序按 stage 展平(与 plan 一致)。 const agents = dagPlan.stages .flatMap((st) => st.agentIds) - .map((id) => ({ agent_id: id, name: nameOf(id), model: modelOf(id) })); + .map((id) => ({ agent_id: id, name: nameOf(id), model: modelOf(id), seat_skill_directive: skillOf(id) })); onConfirm({ agents, mode: "dag", chain: chainMeta, plan: dagPlan, dagExecMode }); return; } - const agents = survivingSeats.map((s) => ({ agent_id: s.agent_id, name: nameOf(s.agent_id), model: modelOf(s.agent_id) })); + const agents = survivingSeats.map((s) => ({ agent_id: s.agent_id, name: nameOf(s.agent_id), model: modelOf(s.agent_id), seat_skill_directive: skillOf(s.agent_id) })); onConfirm({ agents, mode: "chain", chain: chainMeta }); }; diff --git a/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts b/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts index 70bfb38f..bf8e86e1 100644 --- a/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts +++ b/frontend-web/src/roundtable-planning/hooks/useStep2Orchestration.ts @@ -279,6 +279,12 @@ export interface UseStep2OrchestrationOptions { * 智能体」弹窗确认时的 `SeatSelectionResult.seatMode` 决定。缺省 `pro`。 */ selectedMode: SeatMode; + /** + * 每席位「技能识别强化」开关映射 {agentId: bool}(沿用所选业务链条里每个席位的配置)。 + * 按 agentId 查表后透传给该 special 席位 run,与该席位 agent 自身 config.yaml 的同名开关取 + * OR。recommend / 未选链条 → 空 {}(各席位仅靠其自身开关)。 + */ + seatSkillDirectives?: Record; /** * 编排模式: * - `recommend`(默认)—— 总控自由派活循环(`runOrchestration`); @@ -434,6 +440,7 @@ export function useStep2Orchestration( currentStep, selectedModel, selectedMode, + seatSkillDirectives = {}, orchestrationMode, orchestrationPlan, dagExecMode = "fast", @@ -567,6 +574,8 @@ export function useStep2Orchestration( const selectedModelRef = useRef(selectedModel); // 席位执行模式同样打到 ref,让席位调用在编排循环里读到最新值而不重建回调。 const selectedModeRef = useRef(selectedMode); + // 每席位技能识别强化映射(所选业务链条各席位开关)同样打到 ref,席位调用按 agentId 读最新值。 + const seatSkillDirectivesRef = useRef>(seatSkillDirectives); const agentConfigsRef = useRef>(agentConfigs); const agentNameToRoleRef = useRef(agentNameToRole); const threadIdsRef = useRef(threadIds); @@ -606,6 +615,9 @@ export function useStep2Orchestration( useEffect(() => { selectedModeRef.current = selectedMode; }, [selectedMode]); + useEffect(() => { + seatSkillDirectivesRef.current = seatSkillDirectives; + }, [seatSkillDirectives]); useEffect(() => { agentConfigsRef.current = agentConfigs; }, [agentConfigs]); @@ -1602,6 +1614,9 @@ export function useStep2Orchestration( model: perSeatModel || selectedModelRef.current || undefined, // 席位执行模式(快速/思考/专业问答/多智能体问答)→ thinking/reasoning/subagent。 ...seatModeToRequestFields(selectedModeRef.current), + // 会商技能识别强化(该席位在所选业务链条里的开关,按 agentId 查表);与该席位 + // agent 自身开关取 OR。 + seatSkillDirective: seatSkillDirectivesRef.current[a.agentId] ?? false, signal: subAborter.signal, onTextDelta: (text) => a.isParallel ? ingestParallelDelta(a.bubbleId, text) : appendToDialogue(a.bubbleId, text), @@ -2031,6 +2046,9 @@ export function useStep2Orchestration( model: perSeatModel || selectedModelRef.current || undefined, // 席位执行模式 → thinking/reasoning/subagent(与推荐/DAG 路径一致)。 ...seatModeToRequestFields(selectedModeRef.current), + // 会商技能识别强化(该席位在所选业务链条里的开关,按 agentId 查表);与该席位 + // agent 自身开关取 OR。 + seatSkillDirective: seatSkillDirectivesRef.current[seat.agent_id] ?? false, signal: subAborter.signal, onTextDelta: (text) => appendToDialogue(subBubbleId, text), onPhaseChange: (phase, toolName, args) => { @@ -2371,6 +2389,9 @@ export function useStep2Orchestration( model: perSeatModel || selectedModelRef.current || undefined, // 席位执行模式 → thinking/reasoning/subagent(与推荐/链条路径一致)。 ...seatModeToRequestFields(selectedModeRef.current), + // 会商技能识别强化(该席位在所选业务链条里的开关,按 agentId 查表);与该 + // 席位 agent 自身开关取 OR。 + seatSkillDirective: seatSkillDirectivesRef.current[agentId] ?? false, signal: subAborter.signal, // §6:并行席位走 ref 全量累积 + 节流 flush(只渲染选中的);单节点 // stage 实际串行,1 路流直接 setState 不卡,沿用 appendToDialogue。 diff --git a/frontend-web/src/roundtable-planning/lib/business-chain.ts b/frontend-web/src/roundtable-planning/lib/business-chain.ts index 46b8d2a6..dfd68c94 100644 --- a/frontend-web/src/roundtable-planning/lib/business-chain.ts +++ b/frontend-web/src/roundtable-planning/lib/business-chain.ts @@ -29,6 +29,13 @@ export interface ChainSeat { * 的 `handleConfirmAgents`)→ 走现有 per-seat 模型链路。 */ model?: string | null; + /** + * 可选「会商技能识别强化」开关(弱模型补偿)。true = 该席位作为会商子智能体执行时,把其 + * 配置的技能(名称 + SKILL.md 路径 + 必须先 read_file 的硬指令)拼进本轮任务。与该席位 + * 智能体自身的同名开关(智能体编辑里的开关)取 OR。缺省 / false = 关。随 `seats` JSON 落库 + * (无需 DB 列),在链条编辑器里逐席位开关。 + */ + seat_skill_directive?: boolean; } /** 一条可复用的业务链条(与后端 `/api/roundtable-chains` 记录对应)。 */ @@ -80,8 +87,9 @@ export interface SeatSelectionResult { /** * 有序席位 —— 与现有 `handleConfirmAgents` 入参兼容。dag 模式下按 stage 展平排序。 * `model` 为该席位在来源链条里配置的模型覆盖(空 / 缺省 = 跟随全局模型)。 + * `seat_skill_directive` 为该席位在来源链条里配置的「技能识别强化」开关(缺省 = 关)。 */ - agents: Array<{ agent_id: string; name: string; model?: string | null }>; + agents: Array<{ agent_id: string; name: string; model?: string | null; seat_skill_directive?: boolean }>; /** * 决定 Step 2 走哪种编排: * - `recommend` 总控自由派活; @@ -135,6 +143,9 @@ export function buildChainSeatSelection( // 席位模型覆盖(链条配置):按 agent_id 取,空/缺省 = 跟随全局。 const modelById = new Map(chain.seats.map((s) => [s.agent_id, s.model ?? null])); const modelOf = (id: string) => modelById.get(id) ?? null; + // 席位「技能识别强化」开关(链条配置):按 agent_id 取,缺省 = 关。 + const skillById = new Map(chain.seats.map((s) => [s.agent_id, s.seat_skill_directive ?? false])); + const skillOf = (id: string) => skillById.get(id) ?? false; const survivingSeats = chain.seats.filter((s) => existingIds.has(s.agent_id)); if (survivingSeats.length < CHAIN_MIN_SEATS) return null; @@ -156,12 +167,12 @@ export function buildChainSeatSelection( if (hasParallel || hasGoal || hasCoord) { const agents = plan.stages .flatMap((st) => st.agentIds) - .map((id) => ({ agent_id: id, name: nameOf(id), model: modelOf(id) })); + .map((id) => ({ agent_id: id, name: nameOf(id), model: modelOf(id), seat_skill_directive: skillOf(id) })); return { agents, mode: "dag", chain: chainMeta, plan, dagExecMode: "fast", seatMode: chain.seatMode }; } } - const agents = survivingSeats.map((s) => ({ agent_id: s.agent_id, name: nameOf(s.agent_id), model: modelOf(s.agent_id) })); + const agents = survivingSeats.map((s) => ({ agent_id: s.agent_id, name: nameOf(s.agent_id), model: modelOf(s.agent_id), seat_skill_directive: skillOf(s.agent_id) })); return { agents, mode: "chain", chain: chainMeta, seatMode: chain.seatMode }; } diff --git a/frontend-web/src/roundtable-planning/lib/chain-stages.ts b/frontend-web/src/roundtable-planning/lib/chain-stages.ts index a077cc0c..0fc1c20f 100644 --- a/frontend-web/src/roundtable-planning/lib/chain-stages.ts +++ b/frontend-web/src/roundtable-planning/lib/chain-stages.ts @@ -126,6 +126,20 @@ export function setSeatModel(groups: StageGroups, agentId: string, model: string }); } +/** + * 设置某个席位的「会商技能识别强化」开关(不可变,供编辑器席位下拉 onChange)。 + * 按 agent_id 定位,跨 stage 适用。随 `seats` JSON 落库。 + */ +export function setSeatSkillDirective(groups: StageGroups, agentId: string, enabled: boolean): StageGroups { + return groups.map((g) => { + if (!g.seats.some((s) => s.agent_id === agentId)) return g; + return { + ...g, + seats: g.seats.map((s) => (s.agent_id === agentId ? { ...s, seat_skill_directive: enabled } : s)), + }; + }); +} + // ── 变换(均返回新结构,不可变)────────────────────────────────────────────── /** 末尾追加一个**新单席位 stage**(线性追加,pool 点击加入默认行为)。 */ diff --git a/frontend-web/src/roundtable-planning/lib/job-types.ts b/frontend-web/src/roundtable-planning/lib/job-types.ts index 7c1da33e..6c3a9f4e 100644 --- a/frontend-web/src/roundtable-planning/lib/job-types.ts +++ b/frontend-web/src/roundtable-planning/lib/job-types.ts @@ -132,6 +132,11 @@ export interface StartJobPayload { * reasoning/subagent 三字段发给后端。 */ seatMode?: SeatMode; + /** + * 每席位「技能识别强化」开关映射 {agentId: bool}(沿用所选业务链条里每个席位的配置)。 + * 后台席位 run 按 agentId 查表(与各席位智能体自身的同名开关取 OR)决定是否注入。缺省 {}。 + */ + seatSkillDirectives?: Record; } /** 终态集合——SSE/轮询判定作业是否结束。 */ diff --git a/frontend-web/src/roundtable-planning/pages/BusinessChainEditorPage.tsx b/frontend-web/src/roundtable-planning/pages/BusinessChainEditorPage.tsx index 9fd1e2eb..5278e721 100644 --- a/frontend-web/src/roundtable-planning/pages/BusinessChainEditorPage.tsx +++ b/frontend-web/src/roundtable-planning/pages/BusinessChainEditorPage.tsx @@ -37,6 +37,7 @@ import { Plus, Save, Sliders, + Sparkles, SplitSquareVertical, Trash2, UserPlus, @@ -63,6 +64,12 @@ import { import { CSS } from "@dnd-kit/utilities"; import { cn } from "@/lib/utils"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Switch } from "@/components/ui/switch"; import { useDesensitizeSubtree } from "@/roundtable-planning/lib/use-desensitize-subtree"; import { TagSearchBar } from "@/components/workspace/tags/tag-search-bar"; import { ModelNameSelect } from "@/components/workspace/model-name-select"; @@ -105,6 +112,7 @@ import { removeSeat as removeSeatFromGroups, seatExistsInGroups, setSeatModel, + setSeatSkillDirective, setStageGoal, splitSeatToNewStage, stageGroupsToSeats, @@ -366,6 +374,11 @@ export default function BusinessChainEditorPage() { setStageGroups((prev) => setSeatModel(prev, agentId, model)); }, []); + // 席位「会商技能识别强化」开关:编辑器席位下拉 onChange。 + const setSeatSkillDirectiveCb = useCallback((agentId: string, enabled: boolean) => { + setStageGroups((prev) => setSeatSkillDirective(prev, agentId, enabled)); + }, []); + // ── 提示词 AI 优化(总控提示词 / 各 Stage 阶段目标)──────────────────────── const [optimizingCoordinator, setOptimizingCoordinator] = useState(false); const [goalOptimizingIdx, setGoalOptimizingIdx] = useState(null); @@ -564,6 +577,8 @@ export default function BusinessChainEditorPage() { description: live?.description ?? s.description ?? "", // 席位模型覆盖:随席位一起落库(空 → null = 跟随全局)。 model: s.model ?? null, + // 席位「会商技能识别强化」开关:随席位一起落库(缺省 = false 关)。 + seat_skill_directive: s.seat_skill_directive ?? false, }; }); // 总控编排提示:trim 后空串落 null(清空),与后端「空=不注入」一致。 @@ -1131,6 +1146,7 @@ export default function BusinessChainEditorPage() { onMergeSeat={mergeSeatToStage} onSplitSeat={splitSeat} onSeatModelChange={setSeatModelCb} + onSeatSkillDirectiveChange={setSeatSkillDirectiveCb} onStageGoalChange={setGoal} goalOptimizingIdx={goalOptimizingIdx} onOptimizeGoal={handleOptimizeStageGoal} @@ -1309,6 +1325,7 @@ function StagesColumn({ onMergeSeat, onSplitSeat, onSeatModelChange, + onSeatSkillDirectiveChange, onStageGoalChange, goalOptimizingIdx, onOptimizeGoal, @@ -1325,6 +1342,7 @@ function StagesColumn({ onMergeSeat: (agentId: string, targetStageIdx: number) => void; onSplitSeat: (agentId: string) => void; onSeatModelChange: (agentId: string, model: string | null) => void; + onSeatSkillDirectiveChange: (agentId: string, enabled: boolean) => void; onStageGoalChange: (stageIdx: number, goal: string) => void; /** 正在 AI 优化阶段目标的 stage 下标(null = 没有进行中的优化)。 */ goalOptimizingIdx: number | null; @@ -1423,6 +1441,7 @@ function StagesColumn({ onMergeSeat={onMergeSeat} onSplitSeat={onSplitSeat} onSeatModelChange={onSeatModelChange} + onSeatSkillDirectiveChange={onSeatSkillDirectiveChange} onGoalChange={(goal) => onStageGoalChange(stageIdx, goal)} goalOptimizing={goalOptimizingIdx === stageIdx} anyGoalOptimizing={goalOptimizingIdx !== null} @@ -1452,6 +1471,7 @@ function StageSection({ onMergeSeat, onSplitSeat, onSeatModelChange, + onSeatSkillDirectiveChange, onGoalChange, goalOptimizing, anyGoalOptimizing, @@ -1470,6 +1490,7 @@ function StageSection({ onMergeSeat: (agentId: string, targetStageIdx: number) => void; onSplitSeat: (agentId: string) => void; onSeatModelChange: (agentId: string, model: string | null) => void; + onSeatSkillDirectiveChange: (agentId: string, enabled: boolean) => void; onGoalChange: (goal: string) => void; /** 本 Stage 的阶段目标正在 AI 优化中。 */ goalOptimizing: boolean; @@ -1631,6 +1652,7 @@ function StageSection({ onMergeDown={() => onMergeSeat(seat.agent_id, stageIdx + 1)} onSplit={() => onSplitSeat(seat.agent_id)} onModelChange={(model) => onSeatModelChange(seat.agent_id, model)} + onSkillDirectiveChange={(enabled) => onSeatSkillDirectiveChange(seat.agent_id, enabled)} onDetail={() => onSeatDetail(seat.agent_id, seat.name)} /> ))} @@ -1654,6 +1676,7 @@ function SeatStrip({ onMergeDown, onSplit, onModelChange, + onSkillDirectiveChange, onDetail, }: { seat: ChainSeat; @@ -1668,6 +1691,8 @@ function SeatStrip({ onSplit: () => void; /** 席位模型覆盖变更(null = 清除,跟随全局)。 */ onModelChange: (model: string | null) => void; + /** 席位「会商技能识别强化」开关变更。 */ + onSkillDirectiveChange: (enabled: boolean) => void; onDetail: () => void; }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = @@ -1739,8 +1764,41 @@ function SeatStrip({
- {/* 控制:查看详情 / 并入上一阶段 / 独立成阶段 / 并入下一阶段 / 移除 */} + {/* 控制:技能识别强化 / 查看详情 / 并入上一阶段 / 独立成阶段 / 并入下一阶段 / 移除 */}
+ {/* 会商技能识别强化:小图标 → 下拉框(开关 + 说明)。开启 = 高亮。 */} + + + + + +
+
+

会商技能识别强化

+

+ 开启后,该席位作为会商子智能体执行时,会把已配置的技能(含 SKILL.md + 路径与「先 read_file 再用」硬指令)拼进任务,补偿弱模型不识别技能。也可在该智能体编辑里打开(任一即生效)。 +

+
+ +
+
+