feat(parallel-agents): 子智能体禁派活/脚本(防模仿总控) + 面板能力完善
后端 parallel_agents.py:每个并行席位 excluded_tools 增加 agent_orchestration (派活) 与 bash(脚本逃逸),并在任务消息里加「角色边界」护栏——根治弱模型拿到 带「总控/业务链条」语气的任务后模仿总控输出「总控调度指令…」、绕道 glob/bash 翻找派活脚本的问题。新增 /api/parallel-agents/auth/token 取 token 端点 (auth/csrf 豁免)。 parallel-agents-vue 面板:协作澄清卡片、步骤图标/步骤展示、API 与类型完善等。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
3405795371
commit
c230f7a6c6
18 files changed
+1276
-128
No files matched your search
@@ -1,52 +1,95 @@
|
||||
<script setup lang="ts">
|
||||
/** 步骤条 / 思维链卡:折叠展示该气泡运行期间的工具调用步骤(对齐 Step2 MessageStepsCard)。 */
|
||||
import { ref } from "vue";
|
||||
/**
|
||||
* 步骤条 / 思维链卡 —— 1:1 复刻圆桌 Step2 的 MessageStepsCard + ChainOfThought:
|
||||
* slate 边框卡 + 每步「图标列(带竖向连接线) + 中文文案 + 时间 + 参数子节点」。
|
||||
*/
|
||||
import { computed, ref } from "vue";
|
||||
import type { DialogueStep } from "@/types";
|
||||
import { getStepArgs, getStepDisplay } from "@/lib/step-display";
|
||||
import StepIcon from "./StepIcon.vue";
|
||||
|
||||
defineProps<{ steps: DialogueStep[]; streaming?: boolean }>();
|
||||
const props = defineProps<{ steps: DialogueStep[]; streaming?: boolean }>();
|
||||
const open = ref(true);
|
||||
|
||||
function argSummary(args?: Record<string, unknown> | null): string {
|
||||
if (!args) return "";
|
||||
const path = (args as { path?: unknown }).path;
|
||||
if (typeof path === "string") return path;
|
||||
try {
|
||||
const s = JSON.stringify(args);
|
||||
return s.length > 60 ? s.slice(0, 60) + "…" : s;
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
const rows = computed(() =>
|
||||
props.steps.map((s, i) => {
|
||||
const display = getStepDisplay(s.key, s.label, s.args);
|
||||
return {
|
||||
step: s,
|
||||
display,
|
||||
args: getStepArgs(s.key, s.args),
|
||||
// 最后一步在 streaming 时为「进行中」(前景色),其余为已完成(次级色)。
|
||||
active: props.streaming && i === props.steps.length - 1,
|
||||
isLast: i === props.steps.length - 1,
|
||||
};
|
||||
}),
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="pa-surface pa-border mb-2 rounded-lg border p-0.5">
|
||||
<div class="pa-surface pa-border mb-2 w-full gap-1 rounded-lg border p-0.5">
|
||||
<button
|
||||
type="button"
|
||||
class="flex w-full items-center gap-1.5 rounded-md px-2 py-1 text-left text-[11px] font-semibold pa-text-muted"
|
||||
@click="open = !open"
|
||||
>
|
||||
<span
|
||||
class="inline-block transition-transform"
|
||||
:class="open ? 'rotate-90' : ''"
|
||||
>▶</span
|
||||
>
|
||||
<span class="inline-block transition-transform" :class="open ? 'rotate-90' : ''">▶</span>
|
||||
<span>执行步骤({{ steps.length }})</span>
|
||||
<span v-if="streaming" class="pa-spin inline-block">◜</span>
|
||||
</button>
|
||||
<ol v-show="open" class="space-y-0.5 px-2 pb-1.5 pt-0.5">
|
||||
<li
|
||||
v-for="s in steps"
|
||||
:key="s.id"
|
||||
class="flex items-start gap-2 text-[11px] pa-text"
|
||||
|
||||
<div v-show="open" class="space-y-2 px-3 pb-2 pt-0.5">
|
||||
<div
|
||||
v-for="row in rows"
|
||||
:key="row.step.id"
|
||||
class="flex gap-2 text-sm"
|
||||
:class="row.active ? 'pa-text' : 'pa-text-muted'"
|
||||
>
|
||||
<span class="mt-1 inline-block size-1.5 shrink-0 rounded-full" style="background: var(--pa-primary)" />
|
||||
<span class="min-w-0">
|
||||
<span class="font-semibold">{{ s.label }}</span>
|
||||
<span v-if="argSummary(s.args)" class="pa-text-muted"> · {{ argSummary(s.args) }}</span>
|
||||
<span class="pa-text-muted"> · {{ s.ts }}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
<!-- 图标列 + 竖向连接线 -->
|
||||
<div class="relative mt-0.5">
|
||||
<StepIcon :name="row.display.icon" :size="16" />
|
||||
<div
|
||||
v-if="!row.isLast"
|
||||
class="absolute left-1/2 -mx-px w-px"
|
||||
style="top: 26px; bottom: -8px; background: var(--pa-border)"
|
||||
/>
|
||||
</div>
|
||||
<!-- 文案 + 时间 + 参数 -->
|
||||
<div class="min-w-0 flex-1 space-y-1 overflow-hidden">
|
||||
<div class="leading-snug">
|
||||
<span class="font-medium pa-text">{{ row.display.label }}</span>
|
||||
<span class="ml-2 font-mono text-[11px] pa-text-muted">{{ row.step.ts }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 参数子节点(按 kind 渲染,对齐 renderStepArgs) -->
|
||||
<template v-if="row.args">
|
||||
<span
|
||||
v-if="row.args.kind === 'chip'"
|
||||
class="pa-surface pa-border inline-block max-w-full truncate rounded border px-1.5 py-0.5 text-[11px] pa-text-muted"
|
||||
>
|
||||
{{ row.args.text }}
|
||||
</span>
|
||||
<pre
|
||||
v-else-if="row.args.kind === 'code'"
|
||||
class="pa-md max-h-60 overflow-auto rounded-md p-2 text-[11px]"
|
||||
><code>{{ row.args.text }}</code></pre>
|
||||
<span
|
||||
v-else-if="row.args.kind === 'text'"
|
||||
class="line-clamp-2 block text-[11px] leading-snug pa-text-muted"
|
||||
>
|
||||
{{ row.args.text }}
|
||||
</span>
|
||||
<span v-else-if="row.args.kind === 'kv'" class="flex flex-wrap gap-1">
|
||||
<span
|
||||
v-for="p in row.args.pairs"
|
||||
:key="p.k"
|
||||
class="pa-surface pa-border inline-block rounded border px-1.5 py-0.5 text-[11px] pa-text-muted"
|
||||
>
|
||||
<span class="opacity-60">{{ p.k }}:</span> {{ p.v }}
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in new issue
Block a user