mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-12 04:07:34 +00:00
## 缺陷:适配器会永久卡在旧版
writeBundledAdapters 用清单里的 prevHash 判断「盘上有没有被人动过」,
被动的那个就保留。但清单只存 hash ——「内置旧版本的 hash」与
「用户改过的 hash」在清单里长得一模一样。于是:
记了盘上那份当新基线 ⇒ 下次 onDisk == prevHash
⇒ 被误判成「没跟上新版本」⇒ 覆盖掉用户改动
而保留分支里的 cur[name] = onDisk 又会
## 被循环末尾无条件 `cur[name] = sum` 冲掉
⇒ 判「用户改过」后清单仍记内置 hash ⇒ 下次再判一遍「用户改过」
⇒ **永久**停在旧版。日志只有一句「保留用户版本」,
看起来像用户自己的选择,完全看不出是卡住。
本机实测 8 个适配器中招(openai/anthropic/github/groq/mistral/ollama/
kimicode/server),落后内置版 3000~6500 字节,缺的是用量归一化
(cache_read / reasoning_tokens)、流式 tool_calls 等真实修复。
症状最终表现为「模型不听话」「工具调不动」——指不到适配器身上。
## 为什么不能靠「自动覆盖」解决
「旧发行版残留」与「用户手工改过」在文件内容上无法区分(都只是
hash 不等于内置版)。擅自改用户盘上的文件,比落后一个版本更糟。
所以改成**显式 opt-in**:
core.lua.adapter_sync = off(默认) 不碰文件,但告警必须可操作
core.lua.adapter_sync = auto 差异即备份 .bak-<hash8> 后覆盖
零值 = off:忘记注入配置时宁可不动用户文件,也不能默默全量覆盖。
## 告警要可操作,不是「保留用户版本」一句话
教训(2026-10-26 + 2026-11-11 两次):这类静默落后最难查,因为症状
指向模型而不是适配器。现在会给出:数量、名单、影响、三条处理路径
(跟随内核 / 长期定制改 adapter_path / 删掉旧文件)。
长期定制的正道是 `core.llm.sources.<name>.adapter_path`(每源独立可配),
不需要改内置位置的同名文件 —— 这一点也写进告警里。
## 判据 7 条,均经变异验证
TestAdapterSyncDefaultsToOff 零值/未注入必须是 off
(变异:return "off" → "auto" ⇒ 红)
TestOffModeLeavesDiskUntouched off 不碰文件、不产生备份
(变异:case mode=="auto" → case mode!="" ⇒ 红)
TestAutoModeUpdatesWithBackup auto 更新且备份可回滚
TestAutoModeNoRedundantBackup 一致时不重复堆 .bak
TestAdapterStateStableAcrossRestarts 两种模式启停 3 次不漂移
TestManifestCoversAllBundledAdapters 清单不漏项
TestFirstInstallHappensInBothModes off 只「不动已存在文件」,≠不安装
go build / vet / gofmt / go test -race 全绿
## 生产现状(已按用户确认保留更新)
适配器 10/10 与内置一致,8 个 .bak-<hash8> 可回滚
服务 active,NRestarts=0
46 lines
1.4 KiB
Go
46 lines
1.4 KiB
Go
// Package lua 是 lua 模块:Lua VM(LLM 协议适配)。
|
||
//
|
||
// 依赖 config:`initLuaVM(cfg)` 读 cfg.Daemon.DataDir(adapter 目录)。
|
||
package lua
|
||
|
||
import (
|
||
"log"
|
||
"path/filepath"
|
||
|
||
"github.com/JianFeeeee/HologramAgent/internal/kernelmod"
|
||
"github.com/JianFeeeee/HologramAgent/internal/kstate"
|
||
luapkg "github.com/JianFeeeee/HologramAgent/internal/lua"
|
||
)
|
||
|
||
// Module 提供 Lua 协议适配 VM。
|
||
type Module struct{}
|
||
|
||
func (Module) Name() string { return "lua" }
|
||
func (Module) Requires() []string { return []string{kernelmod.FacConfig} }
|
||
func (Module) Provides() []string { return []string{kernelmod.FacLua} }
|
||
|
||
func (Module) Init(ks *kstate.State) error {
|
||
luaVM := luapkg.NewVM(filepath.Join(ks.Cfg.Daemon.DataDir, "adapters"))
|
||
// 适配器同步策略(core.lua.adapter_sync,默认 off)。
|
||
//
|
||
// 读不到就保持零值 = off(保守):忘记注入时宁可「不动用户文件」,
|
||
// 也不能默默把用户的 adapters/ 全量覆盖一遍。
|
||
if ks.CfgReg != nil {
|
||
if v, err := ks.CfgReg.Get("core.lua.adapter_sync"); err == nil && v != nil {
|
||
if s, ok := v.(string); ok {
|
||
luaVM.SetAdapterSync(s)
|
||
}
|
||
}
|
||
}
|
||
if err := luaVM.Start(); err != nil {
|
||
log.Printf("[homed] warning: lua vm init failed: %v", err)
|
||
ks.LuaVM = luaVM
|
||
return nil // 与原语义一致:起不来只告警,仍交回实例
|
||
}
|
||
ks.LuaVM = luaVM
|
||
ks.AddCloser(luaVM.Stop)
|
||
return nil
|
||
}
|
||
|
||
func init() { kernelmod.Register(Module{}) }
|