mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-23 18:38:11 +00:00
feat(webui): 总览显示内核身份、图标全 SVG 化、队列改格槽、阶段管道下方按阶段列事件
四个问题一起改(都出在总览/内核页的展示层,不动内核逻辑):
1) 内核版本不再"看不见"
- 36b577b 改图标 KPI 时把 kernel_name 丢了,只剩一个 "v1.4.0",分不清
是哪个内核、哪次构建。现在 KPI 值给版本号,下面补一行副行
「HomeAgent · <commit>」(.ov-sub)。
- 内核页此前**完全没有构建信息**,现在补一张「构建」卡:内核名/内核版本/
Commit/构建时间/SDK 兼容/源码链接(AGPL §13 的入口页)。
2) 任何位置都不再用 emoji/符号字符充当图标
- 新增 RT_ICO(纯内联 SVG,24x24 / currentColor),替换:阶段节点的循环
标记(原 ↻)、轨迹 chip 的工具/输出标记(原 ⚙/⇥)、"立即运行"(原 ⚡)、
工具卡与思考卡的下拉箭头(原 ▾)。
- CSS 注释里的同类字符一并去掉。
3) 队列不再"空着只有文字"
- 原来画的是宽度百分比进度条:深度为 0 时宽度就是 0,五行只剩文字。
改成 rtSlots 的「车位」式格槽(至少 5 格、最多 16 格,按全场最大深度
缩放),0 时仍有可见形状,占用多少一眼可数;超出格数时给 +N。
- 修掉一个真实的 DOM 结构错误:第五条「排队」队列被写在 .rt-levels 闭合
**之后**,且后面多一个 </div>,多出来的闭合标签会提前关掉祖先节点、
把整块布局撞歪。现在它回到容器内。
4) 每一步管道的事件显示在管道下方对应阶段列里
- 原来是一条拍平的 chip 序列,看不出"这件事发生在哪个阶段"。
现在 .rt-pipe-cols 与上面的阶段节点共用 5 等分栅格,事件按 g(阶段组)
分列落位;实测列中心与节点中心偏差 ≤ 2px。
- 轨迹覆盖全部阶段(输入/思考/工具/输出/完成),同阶段重复的同一条
累加 ×N 而不是刷屏(rtTrailPush)。空列显示一个弱化的「无」。
验证(现网 1400x920,CDP 实测):
- 版本 KPI = v1.4.0+hotfix.0fd4fb1 / HomeAgent · 0fd4fb1;内核页构建卡齐全
- 注入一轮轨迹:col0=输入 col1=思考x2 col2=qq_get_message x3/qq/cmd_run
col3=生成x2 col4=完成,active 节点=工具,×N 计数正常,3 个 chip SVG
- 队列 L3=3/5、排队=2/5 点亮,L3 取到琥珀色 rgb(255,166,87)
- 页面无横向溢出;总览/侧栏/顶栏/内核页渲染文本无 emoji
- go vet 干净,internal/plugins/webui 测试通过
This commit is contained in:
@ -1596,7 +1596,8 @@
|
||||
}
|
||||
.reasoning-card .rc-chev {
|
||||
margin-left: auto;
|
||||
font-size: 10px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: var(--text-muted);
|
||||
transition: transform 0.2s var(--ease-out);
|
||||
}
|
||||
@ -1725,7 +1726,8 @@
|
||||
display: inline-block;
|
||||
}
|
||||
.tool-card .tc-caret {
|
||||
font-size: 10px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: var(--text-muted);
|
||||
transition: transform 0.15s var(--ease-out);
|
||||
}
|
||||
@ -2362,27 +2364,45 @@
|
||||
color: var(--text-secondary);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.rt-level .rt-lv-track {
|
||||
height: 14px;
|
||||
border-radius: 4px;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
overflow: hidden;
|
||||
/* 队列格槽:固定可见的「车位」,占用多少一眼可数。
|
||||
此前是宽度百分比进度条 —— 队列为 0 时宽度为 0,整行只剩文字,
|
||||
看上去就是「这块空着」。 */
|
||||
.rt-level .rt-slots {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
gap: 3px;
|
||||
height: 14px;
|
||||
min-width: 0;
|
||||
}
|
||||
.rt-level .rt-lv-track > i {
|
||||
display: block;
|
||||
height: 100%;
|
||||
transition: width 0.35s var(--ease-out);
|
||||
.rt-level .rt-slots > i {
|
||||
flex: 1 1 0;
|
||||
min-width: 3px;
|
||||
border-radius: 3px;
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
transition:
|
||||
background 0.25s var(--ease-out),
|
||||
box-shadow 0.25s var(--ease-out);
|
||||
}
|
||||
.rt-level .rt-slots.rt-lv-4 > i.on { background: #ff5c7a; box-shadow: 0 0 6px rgba(255, 92, 122, 0.45); }
|
||||
.rt-level .rt-slots.rt-lv-3 > i.on { background: #ffa657; box-shadow: 0 0 6px rgba(255, 166, 87, 0.4); }
|
||||
.rt-level .rt-slots.rt-lv-2 > i.on { background: var(--sakura-400); box-shadow: 0 0 6px rgba(var(--accent-rgb), 0.4); }
|
||||
.rt-level .rt-slots.rt-lv-1 > i.on { background: var(--frost-300); box-shadow: 0 0 6px rgba(136, 192, 208, 0.4); }
|
||||
.rt-level .rt-slots.rt-lv-q > i.on { background: #a3be8c; box-shadow: 0 0 6px rgba(163, 190, 140, 0.4); }
|
||||
.rt-slots-more {
|
||||
flex: 0 0 auto;
|
||||
align-self: center;
|
||||
margin-left: 4px;
|
||||
font-size: 10px;
|
||||
font-weight: 400;
|
||||
color: var(--text-muted);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.rt-level .rt-lv-meta {
|
||||
text-align: right;
|
||||
color: var(--text-muted);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.rt-lv-4 > i { background: #ff5c7a; }
|
||||
.rt-lv-3 > i { background: #ffa657; }
|
||||
.rt-lv-2 > i { background: var(--sakura-400); }
|
||||
.rt-lv-1 > i { background: var(--frost-300); }
|
||||
/* 拓扑图:整张图为 SVG,文字降到最少,其余信息用图形编码
|
||||
(归属=容器/配色、容量=细条、输出能力=圆点、路由=连线)。 */
|
||||
.rt-svg-wrap {
|
||||
@ -2417,9 +2437,6 @@
|
||||
margin-top: 5px;
|
||||
padding-top: 7px;
|
||||
}
|
||||
.rt-level .rt-lv-track.rt-lv-q > i {
|
||||
background: #a3be8c;
|
||||
}
|
||||
/* 中断栈:栈顶在上,做出"层叠现场"的观感 */
|
||||
.rt-stack {
|
||||
display: flex;
|
||||
@ -2666,15 +2683,15 @@
|
||||
}
|
||||
.rt-pipe-nodes {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
}
|
||||
.rt-pipe-node {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
width: 44px;
|
||||
min-width: 0;
|
||||
}
|
||||
.rt-pipe-node > i {
|
||||
width: 11px;
|
||||
@ -2690,11 +2707,20 @@
|
||||
box-shadow 0.25s var(--ease-out);
|
||||
}
|
||||
.rt-pipe-node > b {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 3px;
|
||||
max-width: 100%;
|
||||
font-size: 9px;
|
||||
font-weight: 500;
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
}
|
||||
/* 图标自带 stroke,标签文字不能用下划线(<u> 只为分组) */
|
||||
.rt-pipe-node > b > u {
|
||||
text-decoration: none;
|
||||
}
|
||||
.rt-pipe-node.done > i {
|
||||
background: var(--frost-300);
|
||||
border-color: var(--frost-300);
|
||||
@ -2796,6 +2822,16 @@
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
/* 副行:内核名 + commit。总览只给版本号会分不清是哪个内核、哪次构建。 */
|
||||
.ov-sub {
|
||||
font-size: 10px;
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
min-height: 12px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.ov-lab {
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.05em;
|
||||
@ -2825,20 +2861,49 @@
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* 阶段管道的循环标记与「本轮轨迹」chip 序列。
|
||||
轨迹用不同配色区分:普通工具(⚙)与 output_* 输出通道调用(⇥)。 */
|
||||
/* 阶段管道下方的「每阶段事件」分列。
|
||||
与上面的节点同为 5 等分栅格,所以每一列正好落在它对应阶段的下面;
|
||||
列内 chip 用不同配色区分普通工具与 output_* 输出通道。 */
|
||||
.rt-pipe-cols {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
margin: 4px 0 10px;
|
||||
padding-top: 6px;
|
||||
border-top: 1px dashed rgba(255, 255, 255, 0.09);
|
||||
}
|
||||
.rt-pipe-col {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
gap: 4px;
|
||||
min-width: 0;
|
||||
}
|
||||
/* 行内小图标:一律 SVG,不使用 emoji/符号字符。 */
|
||||
.rt-ico {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
flex: 0 0 auto;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
vertical-align: -1.5px;
|
||||
}
|
||||
.rt-ico-sm {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
}
|
||||
.rt-loop {
|
||||
font-style: normal;
|
||||
display: inline-flex;
|
||||
color: var(--accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
.rt-trail {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
margin: 2px 0 8px;
|
||||
}
|
||||
.rt-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
max-width: 170px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@ -2861,3 +2926,12 @@
|
||||
.rt-chip-stage {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.rt-chip-none {
|
||||
opacity: 0.35;
|
||||
border-style: dashed;
|
||||
}
|
||||
.rt-chip-n {
|
||||
font-style: normal;
|
||||
opacity: 0.75;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
导航项:图标 + 标签。
|
||||
为什么把 data-i18n 挪到内层 span:切语言时那段代码是 `el.textContent = …`,
|
||||
挂在 <a> 上会把图标一起抹掉 —— 只有把标签单独包起来才两全。
|
||||
图标一律 24×24 stroke(currentColor),跟随 active/hover 变色,不额外加一套资源。
|
||||
图标一律 24x24 stroke(currentColor),跟随 active/hover 变色,不额外加一套资源。
|
||||
-->
|
||||
<a class="active" onclick="switchTab('overview')">
|
||||
<svg class="nav-ico" viewBox="0 0 24 24"><path d="M3 3h7v7H3zM14 3h7v5h-7zM14 12h7v9h-7zM3 14h7v7H3z"/></svg>
|
||||
|
||||
@ -782,12 +782,25 @@
|
||||
// 输入 → 行动 ⇄(工具) → 输出 → 结束
|
||||
// (工具那格带循环标记),下面再用一排 chip 记下**本轮真实发生过什么**:
|
||||
// 普通工具与 output_* 输出通道调用用不同配色区分开来。
|
||||
// 页面上**任何位置都不用 emoji/符号字符充当图标** —— 一律内联 SVG,
|
||||
// 24x24 viewBox + currentColor stroke,随主题与状态变色,不额外引资源。
|
||||
var RT_ICO = {
|
||||
in: '<svg class="rt-ico" viewBox="0 0 24 24"><path d="M21 12H8"/><path d="M13 6l-6 6 6 6"/></svg>',
|
||||
act: '<svg class="rt-ico" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3.2"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M5.5 5.5l2.1 2.1M16.4 16.4l2.1 2.1M18.5 5.5l-2.1 2.1M7.6 16.4l-2.1 2.1"/></svg>',
|
||||
tool: '<svg class="rt-ico" viewBox="0 0 24 24"><path d="M14.5 6.5a3.8 3.8 0 0 1 5 5L10 21l-5-5z"/><path d="M14.5 6.5 17.5 9.5"/></svg>',
|
||||
out: '<svg class="rt-ico" viewBox="0 0 24 24"><path d="M4 12h13"/><path d="M13 6l6 6-6 6"/></svg>',
|
||||
done: '<svg class="rt-ico" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>',
|
||||
loop: '<svg class="rt-ico" viewBox="0 0 24 24"><path d="M20.5 12a8.5 8.5 0 1 1-2.5-6"/><path d="M21 3.5V9h-5.5"/></svg>',
|
||||
bolt: '<svg class="rt-ico" viewBox="0 0 24 24"><path d="M13 2 4.5 13.5H11l-1 8.5L18.5 10H12z"/></svg>',
|
||||
caret: '<svg class="rt-ico rt-ico-sm" viewBox="0 0 24 24"><path d="M6 9l6 6 6-6"/></svg>',
|
||||
};
|
||||
|
||||
var RT_PIPE_GROUPS = [
|
||||
{ zh: "输入", en: "in" },
|
||||
{ zh: "行动", en: "act" },
|
||||
{ zh: "工具", en: "tool" },
|
||||
{ zh: "输出", en: "out" },
|
||||
{ zh: "结束", en: "done" },
|
||||
{ zh: "输入", en: "in", ico: "in" },
|
||||
{ zh: "行动", en: "act", ico: "act" },
|
||||
{ zh: "工具", en: "tool", ico: "tool", loop: true },
|
||||
{ zh: "输出", en: "out", ico: "out" },
|
||||
{ zh: "结束", en: "done", ico: "done" },
|
||||
];
|
||||
function rtPhaseGroup(phase) {
|
||||
switch (phase) {
|
||||
@ -813,25 +826,60 @@
|
||||
if (i >= 0) n = n.slice(i + 2);
|
||||
return n.length > 14 ? n.slice(0, 13) + "…" : n;
|
||||
}
|
||||
// rtSlots 画一组「车位」式格槽:槽位数量固定可见,被占用的点亮。
|
||||
//
|
||||
// 为什么不用进度条:队列为 0 时进度条宽度就是 0,整行只剩一串文字,
|
||||
// 看上去就是「这块空着」。格槽在 0 时仍有形状,占用多少一眼可数,
|
||||
// 也不用为了「看得见」而给 0 画一条假进度。
|
||||
function rtSlots(depth, slots, extraCls) {
|
||||
var n = Math.max(5, Math.min(16, slots || 5));
|
||||
var d = depth || 0;
|
||||
var out = '<span class="rt-slots ' + (extraCls || "") + '">';
|
||||
for (var i = 0; i < n; i++) out += '<i class="' + (i < d ? "on" : "") + '"></i>';
|
||||
// 溢出计数必须留在 .rt-slots 内:.rt-level 是 3 列栅格,
|
||||
// 多一个兄弟节点会被挤到下一行,整块队列就串了。
|
||||
if (d > n) out += '<b class="rt-slots-more">+' + (d - n) + "</b>";
|
||||
return out + "</span>";
|
||||
}
|
||||
function rtPipelineHtml(phase, trail) {
|
||||
var g = rtPhaseGroup(phase);
|
||||
var nodes = RT_PIPE_GROUPS.map(function (s, i) {
|
||||
var cls = "rt-pipe-node" + (i === g ? " active" : "");
|
||||
return (
|
||||
'<span class="' + cls + '"><i></i><b>' +
|
||||
__(s.zh, s.en) +
|
||||
(i === 2 ? ' <em class="rt-loop" title="' +
|
||||
__("工具调用会回到行动后,可多次", "tool calls loop back; may repeat") + '">↻</em>' : "") +
|
||||
RT_ICO[s.ico] +
|
||||
"<u>" + __(s.zh, s.en) + "</u>" +
|
||||
(s.loop
|
||||
? ' <em class="rt-loop" title="' +
|
||||
__("工具调用会回到行动后,可多次", "tool calls loop back; may repeat") +
|
||||
'">' + RT_ICO.loop + "</em>"
|
||||
: "") +
|
||||
"</b></span>"
|
||||
);
|
||||
}).join("");
|
||||
var chips = (trail || []).map(function (t) {
|
||||
var kind = t.kind || "stage";
|
||||
return (
|
||||
'<span class="rt-chip rt-chip-' + kind + '" title="' + escHtml(t.label) + '">' +
|
||||
(kind === "output" ? "⇥ " : kind === "tool" ? "⚙ " : "") +
|
||||
escHtml(t.short || t.label) + "</span>"
|
||||
);
|
||||
// 事件按**发生它的阶段**分列,列的横向位置与上面的阶段节点对齐
|
||||
// (同为 5 等分栅格),所以「这一步发生了什么」不需要靠颜色去猜。
|
||||
var cols = RT_PIPE_GROUPS.map(function (s, i) {
|
||||
var items = (trail || []).filter(function (t) {
|
||||
return (t.g | 0) === i;
|
||||
});
|
||||
var body = items.length
|
||||
? items
|
||||
.map(function (t) {
|
||||
var kind = t.kind || "stage";
|
||||
var ico =
|
||||
kind === "output" ? RT_ICO.out : kind === "tool" ? RT_ICO.tool : "";
|
||||
return (
|
||||
'<span class="rt-chip rt-chip-' + kind + '" title="' +
|
||||
escHtml(t.label) + '">' + ico +
|
||||
escHtml(t.short || t.label) +
|
||||
(t.n > 1 ? '<i class="rt-chip-n">x' + t.n + "</i>" : "") +
|
||||
"</span>"
|
||||
);
|
||||
})
|
||||
.join("")
|
||||
: '<span class="rt-chip rt-chip-none">' + __("无", "none") + "</span>";
|
||||
return '<div class="rt-pipe-col">' + body + "</div>";
|
||||
}).join("");
|
||||
return (
|
||||
'<div class="rt-section-title">' +
|
||||
@ -841,10 +889,24 @@
|
||||
'<div class="rt-pipe' + (g < 0 ? " rt-pipe-idle" : "") + '">' +
|
||||
'<div class="rt-pipe-nodes">' + nodes + "</div>" +
|
||||
"</div>" +
|
||||
(chips ? '<div class="rt-trail">' + chips + "</div>" : "")
|
||||
'<div class="rt-pipe-cols">' + cols + "</div>"
|
||||
);
|
||||
}
|
||||
|
||||
// rtTrailPush 把一条「本轮发生过的事」落到它实际发生的阶段列里。
|
||||
// 同一阶段重复出现同一条(如同一工具连调 3 次)只累加计数,不刷屏。
|
||||
function rtTrailPush(g, kind, label, short) {
|
||||
if (!state.stageTrail) state.stageTrail = [];
|
||||
var arr = state.stageTrail;
|
||||
var last = arr.length ? arr[arr.length - 1] : null;
|
||||
if (last && last.g === g && last.kind === kind && last.short === short) {
|
||||
last.n = (last.n || 1) + 1;
|
||||
return;
|
||||
}
|
||||
arr.push({ g: g, kind: kind, label: label, short: short, n: 1 });
|
||||
if (arr.length > 24) arr.shift();
|
||||
}
|
||||
|
||||
// ---- per-agent 负载 ----
|
||||
//
|
||||
// 负载 = 该 agent **自己的**调度器积压折算成的百分比。
|
||||
@ -1096,7 +1158,7 @@
|
||||
// 数据没变 → 早退 → 滑块不动,只能等下一次 /runtime 轮询才追上。
|
||||
var sig = JSON.stringify([
|
||||
sc, residents, channels, inputs, state.pipelinePhase,
|
||||
(state.stageTrail || []).map(function (t) { return t.kind + ":" + (t.short || t.label); }).join(","),
|
||||
(state.stageTrail || []).map(function (t) { return t.g + ":" + t.kind + ":" + (t.short || t.label) + "x" + (t.n || 1); }).join(","),
|
||||
]);
|
||||
if (sig === _rtSig) return;
|
||||
_rtSig = sig;
|
||||
@ -1161,6 +1223,8 @@
|
||||
maxReg = Math.max(maxReg, byLv[L.lv] || 0);
|
||||
maxPre = Math.max(maxPre, preLv[L.lv] || 0);
|
||||
});
|
||||
// 槽位数按全场最大深度缩放(且至少 5 格):0 时也有可见形状,不空着。
|
||||
var qSlots = Math.max(5, Math.min(16, maxQ));
|
||||
h += '<div class="rt-levels">';
|
||||
RT_LEVELS.forEach(function (L) {
|
||||
var depth = q[L.lv] || 0;
|
||||
@ -1168,24 +1232,23 @@
|
||||
var pre = preLv[L.lv] || 0;
|
||||
h +=
|
||||
'<div class="rt-level" title="' + escHtml(L.desc) + '"><span class="rt-lv-name">' + L.name + "</span>" +
|
||||
'<span class="rt-lv-track ' + L.cls + '"><i style="width:' +
|
||||
(depth ? Math.max(4, (depth / maxQ) * 100) : 0) +
|
||||
'%"></i></span>' +
|
||||
rtSlots(depth, qSlots, L.cls) +
|
||||
'<span class="rt-lv-meta">' + depth + " · " +
|
||||
rtMini(reg, maxReg, __("登记", "registered")) +
|
||||
rtMini(pre, maxPre, __("抢占", "preempted")) +
|
||||
"</span></div>";
|
||||
});
|
||||
h += "</div>";
|
||||
// 第五条:排队队列(无级别,纯 FIFO)
|
||||
h += '<div class="rt-level rt-level-queued" title="' + __("排队(无级别,纯 FIFO)", "queued (no priority, FIFO)") + '"><span class="rt-lv-name">' +
|
||||
// 第五条:排队队列(无级别,纯 FIFO)。
|
||||
// 注意:它必须在 .rt-levels **之内**:早前它被写在容器闭合之后,下面又多一个
|
||||
// </div>,多出来的闭合标签会把祖先节点提前关掉,整块布局被撞歪。
|
||||
h +=
|
||||
'<div class="rt-level rt-level-queued" title="' + __("排队(无级别,纯 FIFO)", "queued (no priority, FIFO)") + '"><span class="rt-lv-name">' +
|
||||
__("排队", "queued") + "</span>" +
|
||||
'<span class="rt-lv-track rt-lv-q"><i style="width:' +
|
||||
(ready ? Math.max(4, (ready / maxQ) * 100) : 0) + '%"></i></span>' +
|
||||
rtSlots(ready, qSlots, "rt-lv-q") +
|
||||
'<span class="rt-lv-meta">' + ready + " · FIFO</span></div>";
|
||||
h += "</div>";
|
||||
if (sc.immediate) {
|
||||
h += '<div class="rt-frame">⚡ ' + __("立即运行", "immediate") + ":" +
|
||||
h += '<div class="rt-frame">' + RT_ICO.bolt + " " + __("立即运行", "immediate") + ":" +
|
||||
escHtml(sc.immediate.kind || "") + " #" + sc.immediate.id +
|
||||
'<span class="rt-frame-top">L' + (sc.immediate.level || 0) + "</span></div>";
|
||||
}
|
||||
@ -1290,7 +1353,9 @@
|
||||
icon +
|
||||
'</span><span class="ov-val">' +
|
||||
(dot ? '<i class="ov-dot" id="ov-' + id + '-dot"></i>' : "") +
|
||||
'<b id="ov-' + id + '">—</b></span><span class="ov-lab">' +
|
||||
'<b id="ov-' + id + '">—</b></span>' +
|
||||
'<span class="ov-sub" id="ov-' + id + '-sub"></span>' +
|
||||
'<span class="ov-lab">' +
|
||||
label +
|
||||
"</span></div>"
|
||||
);
|
||||
@ -1336,13 +1401,19 @@
|
||||
ovDot("ov-status-dot", "ov-dot " + (running ? "ok" : "warn"));
|
||||
ovSet("ov-uptime", state.startedAt ? fmtUptime(Date.now() - state.startedAt) : "-");
|
||||
ovSet("ov-plugins", ((k && k.plugins) || []).length || 0);
|
||||
// 内核身份:光有版本号分不清是哪个内核、哪次构建 —— 补上内核名与 commit。
|
||||
// 之前 36b577b 改图标 KPI 时把 kernel_name 丢了,只剩余 "v1.4.0"。
|
||||
var kb = (k && k.build) || {};
|
||||
var kv = kb.version || s.version || "";
|
||||
ovSet("ov-version", kv ? "v" + kv : "—");
|
||||
ovSet(
|
||||
"ov-version",
|
||||
k && k.build && k.build.version
|
||||
? "v" + k.build.version
|
||||
: s.version
|
||||
? "v" + s.version
|
||||
: "—",
|
||||
"ov-version-sub",
|
||||
kv
|
||||
? (kb.kernel_name || "HomeAgent") +
|
||||
(kb.commit && kb.commit !== "unknown"
|
||||
? " · " + String(kb.commit).slice(0, 7)
|
||||
: "")
|
||||
: "",
|
||||
);
|
||||
var llm = (k && k.llm) || {};
|
||||
ovDot("ov-llm-dot", "ov-dot " + (llm.available ? "ok" : "bad"));
|
||||
@ -1850,7 +1921,7 @@
|
||||
"</span>" +
|
||||
pluginHtml +
|
||||
statusHtml +
|
||||
'<span class="tc-caret">▾</span></div>' +
|
||||
'<span class="tc-caret">' + RT_ICO.caret + "</span></div>" +
|
||||
'<div class="tc-detail" style="display:none">' +
|
||||
(argsStr && argsStr !== "{}"
|
||||
? '<div class="tc-args"><div class="tc-detail-label">' +
|
||||
@ -2077,7 +2148,7 @@
|
||||
? __("思考中...", "Thinking...")
|
||||
: __("思考", "Thinking")) +
|
||||
"</span>" +
|
||||
'<span class="rc-chev">▾</span></div>' +
|
||||
'<span class="rc-chev">' + RT_ICO.caret + "</span></div>" +
|
||||
'<div class="reasoning-body" style="display:' +
|
||||
(isStreaming ? "block" : "none") +
|
||||
'">' +
|
||||
@ -3567,17 +3638,17 @@
|
||||
// 阶段轨迹:本轮真实发生过什么,交给阶段管道画成 chip 序列。
|
||||
// 工具调用会反复出现(多轮 toolcall),output_* 单独配色。
|
||||
if (phase === "on_input") {
|
||||
state.stageTrail = [{ kind: "stage", label: __("输入", "input"), short: __("输入", "input") }];
|
||||
state.stageTrail = [];
|
||||
rtTrailPush(0, "stage", __("输入", "input"), __("输入", "input"));
|
||||
} else if (phase === "pre_action") {
|
||||
rtTrailPush(1, "stage", __("组装上下文并思考", "assemble context and think"), __("思考", "think"));
|
||||
} else if (phase === "before_toolcall" && tool) {
|
||||
state.stageTrail.push({
|
||||
kind: tool.indexOf("output_") === 0 ? "output" : "tool",
|
||||
label: tool,
|
||||
short: rtShortTool(tool),
|
||||
});
|
||||
if (state.stageTrail.length > 24) state.stageTrail.shift();
|
||||
var isOut = tool.indexOf("output_") === 0;
|
||||
rtTrailPush(2, isOut ? "output" : "tool", tool, rtShortTool(tool));
|
||||
} else if (phase === "before_output") {
|
||||
rtTrailPush(3, "stage", __("生成回复", "generate reply"), __("生成", "gen"));
|
||||
} else if (phase === "after_output") {
|
||||
state.stageTrail.push({ kind: "stage", label: __("完成", "done"), short: __("完成", "done") });
|
||||
if (state.stageTrail.length > 24) state.stageTrail.shift();
|
||||
rtTrailPush(4, "stage", __("本轮完成", "turn complete"), __("完成", "done"));
|
||||
}
|
||||
state.pipelinePhase = phase;
|
||||
if (state.pipelineTimer) clearTimeout(state.pipelineTimer);
|
||||
@ -4171,7 +4242,45 @@
|
||||
"</p></div>";
|
||||
return;
|
||||
}
|
||||
var b = k.build || {};
|
||||
var html =
|
||||
'<div class="card"><h2>' +
|
||||
__("构建", "Build") +
|
||||
"</h2>" +
|
||||
'<div class="kv-row"><span class="key">' +
|
||||
__("内核", "Kernel") +
|
||||
'</span><span class="val">' +
|
||||
escHtml(b.kernel_name || "HomeAgent") +
|
||||
"</span></div>" +
|
||||
'<div class="kv-row"><span class="key">' +
|
||||
__("内核版本", "Kernel version") +
|
||||
'</span><span class="val">' +
|
||||
escHtml(b.version ? "v" + b.version : "-") +
|
||||
"</span></div>" +
|
||||
'<div class="kv-row"><span class="key">Commit</span><span class="val">' +
|
||||
escHtml(b.commit || "-") +
|
||||
"</span></div>" +
|
||||
'<div class="kv-row"><span class="key">' +
|
||||
__("构建时间", "Build time") +
|
||||
'</span><span class="val">' +
|
||||
escHtml(b.build_time || "-") +
|
||||
"</span></div>" +
|
||||
'<div class="kv-row"><span class="key">' +
|
||||
__("SDK 兼容", "SDK compat") +
|
||||
'</span><span class="val">' +
|
||||
escHtml(b.sdk_compatible || "-") +
|
||||
"</span></div>" +
|
||||
(b.source_url
|
||||
? '<div class="kv-row"><span class="key">' +
|
||||
__("源码", "Source") +
|
||||
'</span><span class="val"><a href="' +
|
||||
escHtml(b.source_url) +
|
||||
'" target="_blank" rel="noopener noreferrer">' +
|
||||
escHtml(b.source_url) +
|
||||
"</a></span></div>"
|
||||
: "") +
|
||||
"</div>";
|
||||
html +=
|
||||
'<div class="card"><h2>' +
|
||||
__("运行时", "Runtime") +
|
||||
"</h2>" +
|
||||
|
||||
Reference in New Issue
Block a user