|
|
b23644ad74
|
fix(webui): 设置接口不再吐内部数据;--webui 覆盖生效;端口占用不再静默成功
三处实测确认的缺陷:
① 设置接口整块吐出聊天记录
plugin.webui.chathistory 是 webui 自己持久化的整段聊天记录(生产实例
实测 5,176,016 字节),躺在插件配置表里被设置接口当普通配置项整块返回,
前端还会把它渲染成一个巨大的文本框。
修复:GET 跳过该键(按插件+键精确判定),PUT 直接 400,避免误改。
② CLI --webui 与 webui.listen_addr 一直是死配置
内核原本在插件加载前写 settings["addr"],但那时 config_<name> 表还没建
(表只在插件注册 def 时创建),PluginSettings.Set 的 INSERT 失败,而错误被
"_ =" 忽略了;随后插件 Start 里 RegisterDef 才建表并写入默认 :8080。
实测:传 "-webui 127.0.0.1:18099" 仍然监听 :8080。
修复:覆盖值改由插件自己接收(webui.SetListenOverride,loadPlugins 前调用),
优先级 CLI > webui.listen_addr(非默认值才算显式配置)> settings["addr"]。
实测修复后:"-webui 127.0.0.1:18099" 正确监听 18099,与生产的 :8080 并存。
③ 端口被占时 webui 静默死亡
Start 在后台 goroutine 里 ListenAndServe,先打印 "listening on" 再尝试绑定,
失败只留一行日志,Start 永远返回 nil → 插件仍被当成加载成功。
修复:net.Listen 同步做,失败即返回 error(交给加载器/守护),
成功后才起 Serve,并打印真实绑定地址。
A/B 实测(两个实例都撞生产的 :8080):
修复前:"listening on :8080" + "server error: address already in use" + LOADED: webui
修复后:"[plugin] start webui: webui: 监听 :8080 失败: ...",不再有 LOADED: webui
效果实测(同一实例,先注入 5,271,690 字节 chathistory):
GET /api/v1/settings 8,244,108 → 28,652 字节(约 1/288)
meta 条数 5,208 → 105,幻影键 0 条
设置页仍正常:?prefix=plugin.webui 返回 8 条 def;普通键 PUT 落库;
校验:GET/PUT 内部键被拒;-webui 覆盖真实生效。
新增测试:TestSettingsNoCrossPluginLeak(跨插件泄漏/幻影键/chathistory 读写)、
TestListenOverrideAndBindFailure(覆盖生效 + 端口占用必须报错)、
TestResolveListenAddrPrecedence(优先级)。
|
2026-09-14 06:54:16 +08:00 |
|
|
|
653e13b470
|
refactor(homed): main() 696 行按启动阶段拆成 25 个阶段函数
main() 原本是一整条 696 行的启动脚本:日志、目录、记忆、配置、Lua、守护、
追踪、内核 API、文本记忆、LLM 源、文档/知识、人格、插件、Agent、ONNX、
IPC、心跳、关停全挤在一个函数里,变量跨 500 行互相引用。
现在 main() 只剩「顺序编排 + 就地交接」(**149 行**,低于 funlen 阈值 150):
opt := parseFlags()
logDir := setupLogging(opt.dataDir)
agentWorkDir := ensureDataDirs(opt.dataDir)
mem, closeMem := initMemoryStack(opt.dataDir)
...
共 25 个阶段调用,实现体在同包 bootstrap.go(一一对应)。
零漂移保证:
* 阶段体逐字取自原 main,只做机械替换(`*dataDir`→参数、`memIdx`→`mem.indexer`);
* 原 main 的每个 defer 都换成一个在**同一位置**注册的 cleanup,
LIFO 释放顺序不变;多资源阶段内部再按原注册顺序取反;
* 语句级比对:原 main 的 525 条可执行语句全部有对应,无遗漏。
仅 3 处为**有意**的结构改写(其余为同义替换):
1. initLuaVM / initTextMemory:「启动成功才 defer Stop」改为
「失败返回 no-op cleanup,成功返回 Stop」——调用点语义不变;
2. startIPCServer:同上(用 started 标志保证失败时不 Stop);
3. resolveBaseAPIKey:把三级兜底 API key 解析提成一个纯函数。
* defaultPrompt 提为包级 const defaultSystemPrompt(不含版本号字面量)。
验证(A/B 实测,不是只跑编译):
* go build ./... / go vet ./cmd/homed/ / go test ./cmd/... ./internal/agent/... ./internal/plugin/... 全绿
* 重构前后二进制各起一次(-data 临时目录,SIGTERM 收尾),日志集合**完全一致**:
63 个注册工具、同名插件全部 loaded、kernel ready、插件逆序关停、'stopped'
—— 差异仅为并发加载插件的打印顺序。
全仓非测试 Go 函数现状:≥300 行 **0 个**,≥200 行 9 个,≥150 行 16 个。
|
2026-09-14 06:30:45 +08:00 |
|