|
|
21db84e8dc
|
fix(webui): 拓扑 +N 提示改用输出带顶部锚点,修提示串行
无输出通道的 agent 那条带上 outTop 在渲染时才确定,而提示行仍在用
循环变量 y(已累加到别的带),所以「+N 更多」会跑到隔壁带上。
改用该带自己的 outTop,并把基线从 +13 收到 +11(紧贴最后一行)。
|
2026-09-14 17:40:46 +08:00 |
|
|
|
0fd4fb1f7a
|
fix(webui): 拓扑按实测容器宽布局 + 字号/截断,修间距失衡与文字难读
三处实机问题:
1) viewBox 固定 640 而容器 ~920,浏览器按 'meet' 把内容顶到左上、右侧空出一大片
—— 观感就是「间距不对」。改为 viewBox 宽 = 实测容器宽、width 用像素值,
缩放恒为 1(已用 getScreenCTM().a 验证)。
2) 文字全是 9-11px + 低对比度硬编码色(#8b90a5)→ 难读。字号提到 10.5-12.5px,
fill/font-size 改走 .tp-* 类,颜色交给 --text-primary/--text-muted 主题变量。
3) 列短的一侧原来顶在带上半、节点居中,连线又长又歪;长通道名还会溢出到邻居身上。
现在两列在带内各自居中、节点块高度参与带高计算(单行带不再把节点名压到下一条带),
长名按估算宽度截断加 …,完整名放 <title> 悬停可见。
另:rtSpark 用的 _rtEdgeIn/_rtEdgeOut 键与取值方式未变,光点动画照旧。
|
2026-09-14 16:51:41 +08:00 |
|
|
|
c252915083
|
feat(webui): 阶段管道改「循环 + 本轮轨迹」,区分工具/输出调用;再砍总览文字
jianf:阶段管道像无记忆的单向滑块,但一轮里会多次 toolcall、也可能多次输出;
且没区分 output_* 调用与普通工具调用;总览仍有一大坨文字。
- 阶段管道不再是单向滑块:#
画成 输入 → 行动 ⇄(工具↻) → 输出 → 结束 的循环结构,当前阶段高亮;
下面用一排 chip 记**本轮真实发生过的序列**(on_input 重置、before_toolcall 追加、
after_output 收尾,最多 24 条)。工具调用会反复出现,循环因此可见。
- 区分调用类型:普通工具 chip 前缀 ⚙(青),output_* 输出通道调用前缀 ⇥(accent 色),
两者配色与图标都不同。
- 文字再收缩:删掉「累计:入队/执行/抢占/挂起/背压」整行;队列标签由
「L4 内核独占…」压成 L4/L3/L2/L1/排队(原描述进 title);各段标题压成
「队列」「栈」「拓扑」;KPI 块标签压成 排队/中断/栈/子代理。
顺带(同类问题):CLI /stop 是人在终端当场下的指令,优先级由默认 L1 提到 L3。
|
2026-09-14 16:31:37 +08:00 |
|
|
|
36b577bff8
|
fix(webui): 总览改静态骨架 + 图标 KPI,彻底去掉整页重建的闪烁
jianf:仍严重闪烁;应彻底摒弃增量重建,用动态图标 + api 数据展示;主页文字太多。
- renderOverview 从「每次 innerHTML 重建整页(含运行态面板)」改成**首帧建一次
静态骨架**,之后 renderAll(每 15s 一次)只 updateOverview —— 只写 textContent
与类名,一个节点都不重建。实测连续两次 renderAll 后 #ov-kpis / #ov-status /
#rt-panel 仍是同一批 DOM 节点,这是"不再闪"的直接判据。
- 主页文字大幅收缩:删掉「系统概览 / LLM 状态 / 记忆状态 / 运行时」四张 kv 文字卡,
改成一排 8 个图标 KPI(状态/运行/插件/版本/LLM/记忆/文档/运行时),状态用彩色
圆点表达,其余只留数字 + 两字标签。
- 运行态面板不再被 renderOverview 清空(去掉 _rtSig=null 与重建),保持连续更新。
|
2026-09-14 16:16:14 +08:00 |
|
|
|
97111778a9
|
feat(webui): 数据查询 API + 前端 keyed 对账,去掉「局部重建」的闪烁
jianf:局部重建的闪烁几乎消不掉,应暴露数据查询 api,前端轮询后增量更新视图,
聊天记录也用这套。
后端(数据查询 api):
- ChatMsg 增加 seq(服务端单调递增、随记录落盘);老记录加载时补 1..n,重启不重编号。
- /api/v1/chat/history 增加 after=<seq> 增量通道:只回 seq 更大的消息,返回 last_seq
作下次游标;一批超 limit 时回**最旧**的一批(回最新会把被挤掉的旧消息永久漏掉)。
普通响应也带 last_seq,客户端首次全量后据此初始化游标。
- 测试 TestChatHistoryIncrementalAfterCursor 钉住「不重不漏 + 截断停在返回的最后一条」。
前端:
- 新增通用 morph():按「子节点位置 + nodeName」递归对账 DOM,同名节点复用、只同步
变化的属性与文本。运行态面板的 put() 由 innerHTML 重建改为 morph —— SVG 圆环、
队列条、数字块这些未变节点不再被替换,CSS 过渡与动画不再从头播。
- 聊天列表改用 keyed commitChatList():按 data-key(服务端 seq / 本地临时 key)对账,
未变消息节点一个字节都不动,只替换真正变化的那条。
- syncChatFromHistory 改走游标:pollChatIncremental() 用 after 拿增量 + tail=1 探尾部
原地更新(工具调用/最终文本是原地改的,不产生新 seq);聊天页可见时 3s 轮询。
|
2026-09-14 15:56:27 +08:00 |
|
|
|
f722498dba
|
feat(webui): 默认配色改黑白 + 设置页新增「外观」区
jianf:默认配色太花,且配色要能在设置页调。
- 新增 mono(黑白灰)配色并设为默认:未选过配色的 localStorage 一律
data-color=mono。黑白下连拓扑归属配色也走灰阶,不至于只剩一张彩图。
- accent 的所有硬编码 rgba(255,127,172,x) 收敛成语义变量 --accent-rgb,
各配色块(sakura/cyan/violet/emerald/amber/blue)各自声明自己的 rgb,
于是换配色时阴影/描边/阴影辉光一起换,不再残留粉色。
- 设置页新增「外观」区(侧栏最前):主题(浅/深)+ 7 个配色圆点 +
背景图 URL/模糊。原先只有侧栏底部一个调色盘图标,找不到。
- 切配色时强制重画运行态(置空 _rtSig),否则拓扑会停在旧色。
|
2026-09-14 15:44:17 +08:00 |
|
|
|
e4d69fa140
|
feat(webui): 总览改版 —— 阶段管道滑块 / per-agent 负载环 / 通道→agent 拓扑与光点
总览页此前是一堆数字与文字块,看不出「这一轮走到哪、谁忙、消息从哪进哪出」。
本次把运行态面板改成以图形为主:
- 阶段管道:七阶段滑块,由 SSE stage 事件驱动,当前阶段高亮、滑块滑过去;
一轮结束(after_output 或 2.5s 无事件)自动回到空闲,不做假动画。
- 队列与中断栈:沿用五条进度条(L1–L4 + 排队),中断栈补一条深度进度条。
- Agent 拓扑:改成「每 agent 一条横带」——左 inputch、中 agent 节点(圆环 = 负载)、
右 outputch,连线即路由;删掉旧的「归属框 + 单个内核盒」画法(看得出哪个子接了哪条输入)。
- 光点动画:channel_input(新增轻量 SSE 事件)沿 inputch→agent 连线跑;
agent_output 沿 agent→outputch 连线跑。用 SMIL animateMotion,不需要 rAF 循环。
- 负载:由该 agent **自己的**调度器积压(排队 / 四级中断 / 中断栈)按级别加权折算,
环形图展示。为此把驻留子的调度器积压透出到状态面(SDK 纯追加字段)。
后端:sdk.ResidentStatus / core.ResidentInfo 增加子 agent 调度器积压四项;
WebUI SSE 增加 channel_input 轻量事件(只带通道名与 agent id,不带正文)。
顺带收口对话区视觉(页签改分段控件、消息间距/气泡区分、输入区分隔线)。
|
2026-09-14 15:33:23 +08:00 |
|
|
|
cdb2ea2207
|
polish(webui): 拓扑图只在容量非默认时写数字(去掉十几行「默认」文字)
|
2026-09-14 11:24:34 +08:00 |
|
|
|
e8d7bb4c06
|
feat(webui): 通道归属合并进拓扑图,整张图改 SVG(少文字、多图形)
上一版把「通道分配(按归属)」单开一段,等于把同一件事拆成两张表——
而通道属于谁是**拓扑的一部分**(左边这些输入口分别被谁接管),拆开反而
看不出关系。按用户要求合并,并整体改成图形化:
- 整张拓扑用 SVG:左侧按归属画出输入通道容器(根=青色虚线框,驻留子=彩色
实线框并标轮次/上下文满),→ 汇集母线 → 内核 → 输出母线 → 右侧输出通道。
**连线即路由**。
- 信息全部改用图形编码:归属=容器/配色、容量=节点内细条(默认容量不画填充)、
输出能力=五个彩色圆点(text/file/image/audio/structured)。
- 文字降到最少:去掉四个数字块的副标题、排队队列那行只留 "FIFO"、
通道行不再写"回程由来源决定"这类说明。
- 段名改为「通道拓扑(连线即路由;左框 = 归属)」。
验证:node --check 通过;go build ./... 干净;webui 测试全绿。
|
2026-09-14 11:22:20 +08:00 |
|
|
|
8756f8d77f
|
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 的才是子容器。
|
2026-09-14 11:08:27 +08:00 |
|
|
|
d502fc1bf5
|
fix(webui): 运行态面板逐段更新(真修「一闪一闪」)+ 补第五条排队队列
1) 上一版只做了整体签名缓存,实测仍会重建:设备通道列表本身就在来回变
(远程设备通道 11→9 条),签名一变就整块 innerHTML,没变的段落(含条
transition)也跟着推倒重来——视觉上仍是闪。改法:外壳只建一次,之后
**逐段**(tiles/levels/stack/owners/topo)比较 HTML,只替换真正变了的那段。
2) 设计是「四条中断队列(L1–L4)+ 一条排队队列」= 五个队列,面板只画了四条:
排队输入这条线在运行态里凭空消失。补第五行「排队(无级别)」,用中性色 +
虚线分隔(它不是优先级,而是另一**类别**),并把它计入条形归一化基准。
段标题从「中断队列(按级别)」改为「队列(四级中断 + 排队)」。
3) 顺带把累计计数(入队/执行/抢占/挂起恢复/拒绝/背压)显式列在数字块下方——
背压是新指标,之前只能看接口看不到面板。
验证:node --check 通过;go build ./... 干净;webui/core/sdk 测试全绿。
|
2026-09-14 11:03:37 +08:00 |
|
|
|
43536ba326
|
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 的归属与「驻留子划走的那条」。
|
2026-09-14 10:55:45 +08:00 |
|
|
|
1ce3a917a5
|
feat(status+webui): 运行态图形化 —— 排队/四级中断队列/中断栈/驻留子/通道拓扑
需求:首页不该只有文字,要能一眼看出内核在忙什么——排队消息数、各级中断
排队与中断栈、驻留子 agent 数量;这些要向**内部 SDK 暴露接口**,供 WebUI 等应用
展示;通道划分也要能画出来。
## 一、内核状态面(internal/sdk,内部 SDK,不受公开 SDK 冻结约束)
* SchedulerStatus 补:
- interrupt_queues[5]:**四级中断队列各自的深度**(下标即级别 1..4,下标 0 恒 0,
这样 level 能直接当数组下标用)。此前只有 pending_interrupts 总数,
看不出"堵在 L1 还是 L4"——四级是抢占优先级,堵在哪级是完全不同的运行状态。
- immediate:刚抢占成功、下一个安全点立即运行的那个中断(此前完全不可见)。
- suspend_frames:中断栈的帧(栈底→栈顶,只给任务标识),depth 之外还能看出
"谁被谁打断"。
- interrupts_by_level / preempts_by_level:各级累计登记数与抢占成功数。
* KernelStatus 补 residents(驻留子运行时视图:状态/轮次/上下文已满/输入通道/允许输出)。
刻意**不带**每个驻留子的 inputch 登记明细——状态面会被反复轮询,明细会让
每次 /status 背上几十 KB;只给表大小,要明细走专门接口。
* ChannelInfo 补 direction(in/out/io)、description、tools、output_caps、caps_text。
此前 collectKernelStatus 只透传 Name/Type,把描述/工具/能力**全丢了**,
前端只能画出一排光秃秃的名字。
## 二、WebUI
* 新增只读 `/api/v1/runtime`:只回运行态三件事(scheduler/residents/channels),
实测 **1.0KB**(/kernel 是 30KB 级)——所以能 3 秒轮询做"实时"感,
而不必反复拉全量状态。
* 首页新增「运行态」面板(纯 CSS + 内联 SVG,前端仍无构建链):
- 四个数字块:排队任务 / 待处理中断 / 中断栈(深度/上限) / 驻留子 Agent,带占比条;
- 四级中断队列条形图:每级"深度 · 登记/抢占",四级语义**照抄内核**
(L4 内核独占 / L3 交互 / L2 消息 / L1 后台),不自己起名字;
- 中断栈层叠图(栈顶在上)+ ⚡立即运行项;
- 通道拓扑:输入通道 → 内核 → 输出通道,双向通道两侧都出现,能力以胶囊标签显示。
* 3 秒轮询只在总览页可见时才发请求;切回总览时 renderAll 会立刻补一次。
## 验证
* 新增 TestSchedulerStatusExposesLevelsAndStack(四级队列/立即项/栈帧/各级计数映射,
并断言"未使用的级别必须为 0"与"下标 0 恒 0")、TestChannelInfoCarriesTopology、
TestRuntimeEndpoint(形状 + 不携带 tools/plugins + 无状态源时 503)。
* go build / vet / agent+core+sdk+plugin+webui 全量测试绿。
* 真实浏览器实测(CDP 驱动,注入运行态样本走真实渲染路径):
数字块 [3, 5, 2/4, 2];四级条 L4=1/L3=2/L2=1/L1=1 与数据一致;
栈帧按"栈底→栈顶"渲染且标出栈顶;通道左右分列、io 通道两侧都出现。
|
2026-09-14 09:05:14 +08:00 |
|
|
|
c0e9dc1818
|
fix(webui): 聊天记录不再"每次都发完整记录",并修掉视口跳顶
两个都是你指出的症状,都定位到了具体代码路径。
① 「每次都发完整聊天记录」
a) API 缺省值错了:/api/v1/chat/history 的 limit 缺省是 0 = **不限制**,
于是任何不带 limit 的调用每次都拿到整段记录。实测(126 条):
不带 limit 635,297 字节;现在默认只回一页 180,668 字节。
显式 limit=0 仍可整取(逃生口)。WebUI/GUI 本来都带 limit,不受影响。
b) 前端 30s 轮询(以及每次 SSE 报错)都直接拉一页 40 条:
浏览器实测单次 180,813 字节。现在先做"尾巴探测"(limit=1,362 字节),
尾巴一致就直接跳过;不一致才拉整页。
② 「聊天记录会跳到顶部」——两条会导致视口丢失的路径都堵上
a) syncChatFromHistory 在"找不到重合点"时直接 `state.messages = serverMsgs`:
服务端只回一页,而本地可能已经向上翻了好几页;一覆盖,容器立刻变矮,
视口被夹回顶部,用户翻过的旧消息也凭空消失。现在只在服务端页**不短于**本地时
才整体替换。
b) renderChat 全量重建 innerHTML 后,仅在粘底时滚到底;非粘底(用户正在向上读)
时位置没人管。改为重建前记住 scrollTop、非粘底时原样还回去。
浏览器实测(CDP 驱动真实页面,126 条历史):
* 15s/30s 定时器跑满 40s:聊天区滚动位置 **0 px 变化**,未跳顶;
* 期间 chat/history 请求:limit=1 × 2(各 362 字节)+ 首屏 limit=40 一次;
* 控制台无报错;新增消息后轮询仍能正确并进来(尾巴探测→拉整页→合并)。
测试:新增 TestChatHistoryDefaultIsPaged(默认一页 / has_more / limit=0 整取 / 显式分页)。
顺带修测试串味:迁移用例往 os.TempDir() 写共享历史文件,会让其它用例的
NewHandler 加载到脏历史(表现为条数多 1);现在各用例用自己的临时文件。
|
2026-09-14 08:06:16 +08:00 |
|
|
|
764939ed90
|
refactor(webui): dashboard.html 6637 行拆成「外壳 + 样式 + 脚本」
前端刻意没有构建链(纯 CSS + Vanilla JS,go:embed 进二进制),所以拆法是:
外壳 dashboard.html 留 {{DASHBOARD_CSS}} / {{DASHBOARD_JS}} 两个占位符,
init() 启动时把两份资产原样填回去 —— **发出的 HTML 与拆分前逐字节一致**,
但 6637 行的单文件变成三份,便于编辑与评审。
dashboard.html 168 行 外壳(head/body 结构 + 两个占位符)
dashboard.css 2099 行 样式
dashboard.js 4371 行 脚本
逐字节校验(三重):
* 组装结果 sha256 == git HEAD 里拆分前的 dashboard.html;
* 真实实例 GET /(带 API key)返回体 sha256 同上:0ef14b49…c053;
* 新增 TestDashboardAssetsSplit:占位符必须存在、样式/脚本不得再内联回外壳、
组装结果不得残留占位符且必须含样式与脚本特征串。
按行号切片时踩过一次坑并已修正:`</style>`/`</script>` 两个闭合标签被切掉
(正好少 27 字节)——正是因为当时少了逐字节校验,现在把它固化成断言。
|
2026-09-14 07:17:23 +08:00 |
|