diff --git a/docs/v2/agents_dynamic.png b/docs/v2/agents_dynamic.png new file mode 100644 index 0000000..022e5c4 Binary files /dev/null and b/docs/v2/agents_dynamic.png differ diff --git a/docs/v2/dag_fixed.png b/docs/v2/dag_fixed.png new file mode 100644 index 0000000..7e37f59 Binary files /dev/null and b/docs/v2/dag_fixed.png differ diff --git a/static/app.js b/static/app.js index 5fe6f52..338c37a 100644 --- a/static/app.js +++ b/static/app.js @@ -353,6 +353,11 @@ function drawDag() { const ready = tasks.filter(t => (t.status === 'todo' || t.status === 'failed') && (!t.depends_on || t.depends_on.every(d => idMap[d]?.status === 'done'))); const body = $('#tab-body'); if (!body) return; + const NW = 140, NHW = 70; // 节点宽 / 半宽 + const dagText = t => { + const raw = `#${t.id} ${t.title}`; + return raw.length > 13 ? raw.slice(0, 13) + '…' : raw; + }; body.innerHTML = `
共 ${tasks.length} 个节点 · ${edges.length} 条依赖边${ready.length ? ` · ${ready.length} 个任务就绪` : ''} · 拖节点调位 / 滚轮缩放 / 拖空白平移 / 双击复位 @@ -367,14 +372,14 @@ function drawDag() { if (!a || !b) return ''; const mx = (a.x + b.x) / 2; const act = idMap[e.from].status === 'done'; - return ``; + return ``; }).join('')} ${tasks.map(t => { const p = dagState.pos[t.id]; const col = colors[t.status]; return ` - - #${t.id} ${esc(t.title).slice(0, 10)} + + ${esc(dagText(t))} ${STATUS[t.status].label}${t.depends_on?.length ? ' · 前置' + t.depends_on.length : ''} `; }).join('')} @@ -429,7 +434,7 @@ function bindDagEvents() { const nid = Number(g.dataset.id); const pp = s.pos[nid]; if (!pp) return; - g.querySelector('rect').setAttribute('x', pp.x - 55); + g.querySelector('rect').setAttribute('x', pp.x - 70); g.querySelector('rect').setAttribute('y', pp.y - 24); const ts = g.querySelectorAll('text'); ts[0].setAttribute('x', pp.x); ts[0].setAttribute('y', pp.y - 2); @@ -451,7 +456,7 @@ function bindDagEvents() { const path = svgEl.querySelector(`path[data-e="${d}-${tid}"]`); if (!path) return; const mx = (b.x + a.x) / 2; - path.setAttribute('d', `M${b.x + 55},${b.y} C${mx},${b.y} ${mx},${a.y} ${a.x - 55},${a.y}`); + path.setAttribute('d', `M${b.x + 70},${b.y} C${mx},${b.y} ${mx},${a.y} ${a.x - 70},${a.y}`); }); }); }); @@ -1124,6 +1129,20 @@ function renderAgents() { const {modes, workers, runs} = agentsCtx; const wOpts = workers.map(w => ``).join(''); + // 各模式专属参数定义(m: 适用模式列表) + const paramRows = [ + {id: 'ag-workers', m: 'all', html: ``}, + {id: 'ag-rounds', m: 'review', html: ``}, + {id: 'ag-pass', m: 'review', html: ``}, + {id: 'ag-debate-rounds', m: 'debate', html: ``}, + {id: 'ag-stances', m: 'debate', html: ``}, + {id: 'ag-context', m: 'all', html: ``}, + ]; + const modeHints = { + supervisor: '💡 第 1 个 Agent 担任主管(负责拆解与最终合成),其余 Agent 并行执行子任务。', + review: '💡 第 1 个 Agent 为执行者,第 2 个为评审(只选 1 个时由同一 Agent 自评)。低于分数线自动返工,最多重试所选轮次。', + debate: '💡 除最后 1 个 Agent 为裁判外,其余均为辩手;立场按顺序分配,裁判综合裁决输出共识。', + }; $('#main').innerHTML = `

多 Agent 协作主管 / 评审 / 辩论 三种团队协作模式

${modes.map(m => ` @@ -1131,25 +1150,18 @@ function renderAgents() {
${m.icon}
${esc(m.name)}
${esc(m.desc)}
-
${m.params.length} 项参数
+
${m.id === 'supervisor' ? '拆解+委派+合成' : m.id === 'review' ? '产出+评审+返工' : '立论+质询+裁决'}
`).join('')}
⚡ 发起协作运行
- - - - - - - -
-
- - 💡 评审模式第 1 个 Agent 为执行者,第 2 个(若有)为评审;辩论模式最后一个为裁判。 + + ${paramRows.map(r => r.html).join('')}
+
${modeHints.supervisor}
+
📋 运行记录
@@ -1166,10 +1178,21 @@ function renderAgents() { `).join('') || '暂无运行记录'}
`; - $('#ag-mode').addEventListener('change', e => { - const m = modes.find(x => x.id === e.target.value); - toast('已选择:' + m.name, ''); - }); + // 模式切换:动态显示/隐藏专属参数 + const applyMode = mode => { + $$('.form-grid [data-modes]').forEach(el => { + const ms = el.dataset.modes.split(','); + el.style.display = (ms.includes('all') || ms.includes(mode)) ? '' : 'none'; + }); + $('#ag-hint').textContent = modeHints[mode] || ''; + $$('.mode-card').forEach(c => c.style.outline = c.dataset.mode === mode ? '2px solid var(--accent)' : ''); + }; + $('#ag-mode').addEventListener('change', e => applyMode(e.target.value)); + $$('.mode-card').forEach(c => c.addEventListener('click', () => { + $('#ag-mode').value = c.dataset.mode; + applyMode(c.dataset.mode); + })); + applyMode($('#ag-mode').value); $('#ag-run').addEventListener('click', async () => { const mode = $('#ag-mode').value; const topic = $('#ag-topic').value.trim(); diff --git a/static/style.css b/static/style.css index fd52878..1448fb8 100644 --- a/static/style.css +++ b/static/style.css @@ -133,10 +133,11 @@ tr:hover td{background:var(--panel2)} .tabs a.active{color:var(--accent);border-bottom-color:var(--accent)} .dag-box{background:var(--panel);border:1px solid var(--border);border-radius:12px;overflow:hidden;height:520px;position:relative;touch-action:none;user-select:none;cursor:grab} .dag-box svg{display:block;transition:transform .05s linear} -.dag-node{fill:var(--panel2);stroke:var(--border);stroke-width:1.5;rx:10;cursor:pointer} +.dag-node{stroke:var(--border);stroke-width:1.5;rx:10;cursor:grab} .dag-node:hover{stroke:var(--accent)} -.dag-label{font-size:12px;fill:var(--text);text-anchor:middle} -.dag-sub{font-size:10px;fill:var(--muted);text-anchor:middle} +.dag-node rect{stroke-width:1.5;rx:10} +.dag-label{font-size:12px;fill:#ffffff;text-anchor:middle;pointer-events:none} +.dag-sub{font-size:10px;fill:rgba(255,255,255,.78);text-anchor:middle;pointer-events:none} .dag-edge{stroke:var(--border);stroke-width:1.5;fill:none;marker-end:url(#arrow)} .dag-edge.act{stroke:var(--accent)} .alert-row{border-left:3px solid var(--border);padding:12px 14px;margin-bottom:8px;background:var(--panel2);border-radius:0 10px 10px 0;cursor:pointer}