fix(webui): 通道归属把「根 agent id」与驻留子分开(根不再被标成「驻留子 main」)

实测(创建一个驻留子 uitest 并把 timer 划给它)暴露的归类错误:
inputch 的 owner 在登记表里可以是**根 agent 自己的 id**(如 "main")——
child/<id> 这条就是 owner="main"。前端只按「owner 非空」判为驻留子,
于是根自己那条被标成「驻留子 main」,而同一条通道在 residents 里根本不存在。

改法:
- /api/v1/runtime 补 agent_id(根 agent 的 id);
- 前端把 owner == 根 id 与 owner == "" 归一成同一组「根 agent / 内核默认」,
  只有既非空又非根 id 的才是子容器。
This commit is contained in:
JianFeeeee
2026-09-14 11:07:28 +08:00
parent d502fc1bf5
commit 8756f8d77f
2 changed files with 21 additions and 7 deletions

View File

@ -786,8 +786,15 @@
});
var owners = [];
var byOwner = {};
// 根 agent 的 id登记表里根自己的 owner 就是它(如 "main")。
// 不把它跟驻留子分开,根自己的通道会被标成「驻留子 main」——实测踩过。
var rootID = rt.agent_id || "";
var isChild = function (o) { return o !== "" && o !== rootID; };
inputs.forEach(function (c) {
// owner == 根 agent id 与 owner == "" 是同一件事(都是归根 agent / 内核默认),
// 归一成一组,否则同一个根会画出两个容器。
var o = c.owner || "";
if (o === rootID) o = "";
if (!byOwner[o]) {
byOwner[o] = [];
owners.push(o);
@ -798,14 +805,14 @@
// 与「子不存在」无法区分。
residents.forEach(function (r) {
var o = r.id || "";
if (o && !byOwner[o]) {
if (o && o !== rootID && !byOwner[o]) {
byOwner[o] = [];
owners.push(o);
}
});
owners.sort(function (a, b) {
if (a === "") return -1;
if (b === "") return 1;
if (a === "" || a === rootID) return -1;
if (b === "" || b === rootID) return 1;
return a < b ? -1 : 1;
});
if (!owners.length) {
@ -819,10 +826,13 @@
if (r.id === o) res = r;
});
}
h += '<div class="rt-owner' + (o ? " rt-owner-child" : "") + '">';
var child = isChild(o);
h += '<div class="rt-owner' + (child ? " rt-owner-child" : "") + '">';
h += '<div class="rt-owner-head"><span class="rt-owner-name">' +
(o ? "▸ " : "◆ ") +
(o ? __("驻留子 ", "resident ") + escHtml(o) : __("根 agent / 内核默认", "root agent / kernel default")) +
(child ? "▸ " : "◆ ") +
(child
? __("驻留子 ", "resident ") + escHtml(o)
: __("根 agent", "root agent") + (o ? " " + escHtml(o) : "") + __(" / 内核默认", " / kernel default")) +
'</span><span class="rt-owner-meta">' + list.length + " " + __("条通道", "channels") +
(res ? " · " + __("轮次", "rounds") + " " + (res.rounds || 0) : "") +
(res && res.context_full ? ' <span class="rt-badge-warn">' + __("上下文已满", "ctx full") + "</span>" : "") +

View File

@ -261,7 +261,11 @@ func (h *Handler) handleRuntime(w http.ResponseWriter, r *http.Request) {
return
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"uptime": ks.Uptime,
"uptime": ks.Uptime,
// agent_id 是**根 agent 的 id**。前端靠它把 inputch 的 owner 归类:
// 归属登记表里根 agent 的 id如 "main")与驻留子 id 长得一样,
// 不区分就会把根自己的通道标成「驻留子 main」。
"agent_id": ks.AgentID,
"scheduler": ks.Scheduler,
"residents": ks.Residents,
"channels": ks.Channels,