feat(admin): Agent监控/后台思考接WS实时 + 真流程图
- 新增 FlowGraph.tsx: SVG 自绘 DAG(分层布局/bezier边/箭头/按status着色,零新增依赖) - Agents.tsx: 上下文查询接真后端(task_output_query→task_output);终止/重派诚实标需后端M10+,绝不伪造 - Backthink.tsx: 链路导图接 FlowGraphView;干预诚实标需后端M10+ - 控制项一律 useAuditStore.log 记 ok/error,未接入不伪造成功
This commit is contained in:
1 parent
4ad1e465da
commit
ba8ff835cd
3 files changed
+290
-21
No files matched your search
@@ -6,6 +6,7 @@ import { Button, EmptyState, Surface, Tag, type TagTone } from "../../components
|
||||
import { sendUp } from "../../lib/ws";
|
||||
import { useAuditStore } from "../audit";
|
||||
import { Icon } from "../../components/Icon";
|
||||
import { FlowGraphView } from "./FlowGraph";
|
||||
|
||||
const statusTone: Record<AgentStatus, { label: string; tone: TagTone }> = {
|
||||
idle: { label: "空闲", tone: "neutral" },
|
||||
@@ -15,8 +16,21 @@ const statusTone: Record<AgentStatus, { label: string; tone: TagTone }> = {
|
||||
error: { label: "错误", tone: "err" },
|
||||
};
|
||||
|
||||
function AgentCard({ agent, onKill }: { agent: AgentInfo; onKill: (id: string) => void }): React.ReactNode {
|
||||
function AgentCard({ agent }: { agent: AgentInfo }): React.ReactNode {
|
||||
const meta = statusTone[agent.status] ?? statusTone.idle;
|
||||
const log = useAuditStore((s) => s.log);
|
||||
const [hint, setHint] = useState<string | null>(null);
|
||||
|
||||
const query = () => {
|
||||
const ok = sendUp({ type: "task_output_query", data: { taskId: agent.id } });
|
||||
log(`agent.query:${agent.id}`, ok ? "ok" : "error");
|
||||
setHint(ok ? "已请求上下文,输出见下方「任务日志」。" : "WS 未连接,无法查询。");
|
||||
};
|
||||
const kill = () => {
|
||||
log(`agent.kill:${agent.id}`, "error");
|
||||
setHint("终止子代理需后端 M10+ 能力接入,当前为只读展示,未执行任何操作。");
|
||||
};
|
||||
|
||||
return (
|
||||
<Surface className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -40,13 +54,14 @@ function AgentCard({ agent, onKill }: { agent: AgentInfo; onKill: (id: string) =
|
||||
))}
|
||||
{agent.message ? <div className="text-xs text-[var(--mu-text-mid)]">{agent.message}</div> : null}
|
||||
<div className="flex gap-2">
|
||||
<Button size="sm" variant="ghost" onClick={() => sendUp({ type: "task_output_query", data: { taskId: agent.id } })}>
|
||||
<Button size="sm" variant="ghost" onClick={query}>
|
||||
上下文查询
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => onKill(agent.id)}>
|
||||
<Button size="sm" variant="outline" onClick={kill}>
|
||||
终止
|
||||
</Button>
|
||||
</div>
|
||||
{hint ? <div className="text-xs text-[var(--mu-text-lo)]">{hint}</div> : null}
|
||||
</Surface>
|
||||
);
|
||||
}
|
||||
@@ -58,6 +73,7 @@ export function AgentsModule(): React.ReactNode {
|
||||
const clearTaskLog = useAppStore((s) => s.clearTaskLog);
|
||||
const log = useAuditStore((s) => s.log);
|
||||
const [tab, setTab] = useState<"main" | "sub">("main");
|
||||
const [respawnHint, setRespawnHint] = useState(false);
|
||||
|
||||
const subAgents = agents.filter((a) => a.id !== "main");
|
||||
const list = tab === "main" ? agents.filter((a) => a.id === "main") : subAgents;
|
||||
@@ -71,8 +87,8 @@ export function AgentsModule(): React.ReactNode {
|
||||
<Button
|
||||
variant="soft"
|
||||
onClick={() => {
|
||||
log("agent.respawn", "ok");
|
||||
alert("重派(占位):后端 M10+ 提供子代理重派。");
|
||||
log("agent.respawn", "error");
|
||||
setRespawnHint(true);
|
||||
}}
|
||||
>
|
||||
重派
|
||||
@@ -80,22 +96,21 @@ export function AgentsModule(): React.ReactNode {
|
||||
}
|
||||
/>
|
||||
|
||||
{respawnHint ? (
|
||||
<Notice tone="warn">子代理重派需后端 M10+ 能力接入,当前未启用;可先通过「上下文查询」与任务日志查看已运行子代理。</Notice>
|
||||
) : null}
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<TabPill active={tab === "main"} onClick={() => setTab("main")}>主会话</TabPill>
|
||||
<TabPill active={tab === "sub"} onClick={() => setTab("sub")}>子代理 ({subAgents.length})</TabPill>
|
||||
</div>
|
||||
|
||||
{flowGraph ? (
|
||||
<Surface className="flex flex-wrap items-center gap-3">
|
||||
{flowGraph.nodes.map((n, i) => (
|
||||
<div key={n.id} className="flex items-center gap-3">
|
||||
<Tag tone={n.status === "running" ? "accent" : "neutral"}>{n.label}</Tag>
|
||||
{i < flowGraph.nodes.length - 1 ? <span className="text-[var(--mu-text-lo)]">→</span> : null}
|
||||
</div>
|
||||
))}
|
||||
<Surface gap="sm">
|
||||
<FlowGraphView graph={flowGraph} />
|
||||
</Surface>
|
||||
) : (
|
||||
<Notice>流程图占位 —— 连接 /ws/chat 后按 graph_update 事件渲染。</Notice>
|
||||
<Notice>暂无流程图数据 —— 连接 /ws/chat 后按 graph_update 事件实时渲染。</Notice>
|
||||
)}
|
||||
|
||||
{list.length === 0 ? (
|
||||
@@ -103,7 +118,7 @@ export function AgentsModule(): React.ReactNode {
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{list.map((a) => (
|
||||
<AgentCard key={a.id} agent={a} onKill={(id) => { log(`agent.kill:${id}`, "ok"); alert(`终止 ${id}(占位)`); }} />
|
||||
<AgentCard key={a.id} agent={a} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
@@ -123,7 +138,9 @@ export function AgentsModule(): React.ReactNode {
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
<Notice>子代理链上下文查询、终止/重派、流程图导出需后端 M10+ 提供。</Notice>
|
||||
<Notice>
|
||||
任务日志实时来自 task_output 事件;「上下文查询」通过 task_output_query 上行帧查询真实输出(已接后端)。终止 / 重派需后端 M10+ 提供,当前为只读展示。
|
||||
</Notice>
|
||||
</Surface>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user