mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-24 10:58:13 +00:00
fix(webui): 运行态面板不再闪、通道分配带归属(含驻留子)、改图形化
三个用户可见问题,逐个说明根因与改法。 1) 首页「一闪一闪」——运行态每 3s 轮询一次,renderRuntime 无条件重建 #rt-panel 的 innerHTML:数据没变也把整块 DOM(含各级条的 transition) 推倒重来。改法:缓存数据签名(**不含 uptime**——它每秒都变,带上等于没缓存), 签名相同直接 return,一个字节都不动。另:renderOverview 会整块重建 #rt-panel(面板本身是空的),所以那里必须让签名失效,否则空面板填不上。 2) 通道分配只显示内核/根 agent,看不见驻留子——根因是状态面只暴露了设备能力 (KernelStatus.Channels,来自 iom.ListChannels),而「这条输入归谁」是 ChannelRegistry 的属性(InputChannel.Owner/Capacity/Output),从未出过内核。 而登记表本来就是根 agent 与驻留子**共用同一份**,所以数据一直都在,只是没画。 改法:KernelStatus 新增 InputChannels(+ sdk.InputChannelInfo), /api/v1/runtime 带出 input_channels;前端把它按 owner 分进「归属容器」, 驻留子即使一条 inputch 都没划到也照样出现在图里(否则"子存在但看不见" 与"子不存在"无法区分),并显示其 allowed_outputs / 轮次 / 上下文满标记。 3) 「这些信息明明可以图形化」——四级中断的登记/抢占由纯文本改成并排迷你条; 通道分配用归属容器 + 容量滑块(轨道/填充/把手/读数),并把回程通道、 注册插件做成胶囊标签。设备能力拓扑(原有)保留。 验证:go build/vet 干净;go test ./internal/agent/... ./internal/plugin/... ./internal/sdk/... ./cmd/... 全绿;node --check dashboard.js 语法通过。 TestRuntimeEndpoint 扩展为同时钉住 input_channels 的归属与「驻留子划走的那条」。
This commit is contained in:
@ -1409,6 +1409,13 @@ func TestRuntimeEndpoint(t *testing.T) {
|
||||
},
|
||||
Residents: []sdk.ResidentStatus{{ID: "r1", State: "running", Rounds: 3}},
|
||||
Channels: []sdk.ChannelInfo{{Name: "webui", Type: "1", Direction: "out", Ready: true, OutputCaps: 7, CapsText: "[text file image]"}},
|
||||
// inputch 的登记与归属:必须带出**驻留子划走的那条**(owner=子 id)——
|
||||
// 只回设备能力(channels)就无法回答「这条输入归谁」,驻留子的通道分配
|
||||
// 在界面上完全不可见(本次修的缺口)。
|
||||
InputChannels: []sdk.InputChannelInfo{
|
||||
{Name: "qq", Plugin: "qq", Capacity: 32, Output: "qq"},
|
||||
{Name: "timer", Plugin: "timer", Owner: "r1", Capacity: 8},
|
||||
},
|
||||
}
|
||||
s := testSDK(sdk.SDKConfig{
|
||||
Settings: sdk.NewSettings("webui", internalConfig.NewConfigRegistry("")),
|
||||
@ -1424,9 +1431,10 @@ func TestRuntimeEndpoint(t *testing.T) {
|
||||
t.Fatalf("expected 200, got %d", w.Code)
|
||||
}
|
||||
var out struct {
|
||||
Scheduler sdk.SchedulerStatus `json:"scheduler"`
|
||||
Residents []sdk.ResidentStatus `json:"residents"`
|
||||
Channels []sdk.ChannelInfo `json:"channels"`
|
||||
Scheduler sdk.SchedulerStatus `json:"scheduler"`
|
||||
Residents []sdk.ResidentStatus `json:"residents"`
|
||||
Channels []sdk.ChannelInfo `json:"channels"`
|
||||
InputChannels []sdk.InputChannelInfo `json:"input_channels"`
|
||||
}
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &out); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
@ -1446,6 +1454,25 @@ func TestRuntimeEndpoint(t *testing.T) {
|
||||
if len(out.Channels) != 1 || out.Channels[0].Direction != "out" {
|
||||
t.Fatalf("通道方向丢失:%+v", out.Channels)
|
||||
}
|
||||
// 通道分配:既要带归属,也要带**驻留子划走的那条**
|
||||
if len(out.InputChannels) != 2 {
|
||||
t.Fatalf("input_channels 应回 2 条,实际 %+v", out.InputChannels)
|
||||
}
|
||||
var childCh, rootCh *sdk.InputChannelInfo
|
||||
for i := range out.InputChannels {
|
||||
switch out.InputChannels[i].Owner {
|
||||
case "":
|
||||
rootCh = &out.InputChannels[i]
|
||||
case "r1":
|
||||
childCh = &out.InputChannels[i]
|
||||
}
|
||||
}
|
||||
if rootCh == nil || rootCh.Name != "qq" || rootCh.Capacity != 32 || rootCh.Output != "qq" {
|
||||
t.Fatalf("根 agent 的 inputch 归属/容量/回程丢失:%+v", rootCh)
|
||||
}
|
||||
if childCh == nil || childCh.Name != "timer" || childCh.Capacity != 8 {
|
||||
t.Fatalf("驻留子划走的 inputch 未带出(这正是本次修的缺口):%+v", childCh)
|
||||
}
|
||||
// 只回运行态:不该把 tools/plugins 这类大块带上
|
||||
if strings.Contains(w.Body.String(), "\"tools\"") || strings.Contains(w.Body.String(), "\"plugins\"") {
|
||||
t.Fatal("/runtime 不应携带 tools/plugins(那是 /kernel 的内容)")
|
||||
|
||||
Reference in New Issue
Block a user