mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 09:28:14 +00:00
fix(config): 全新安装的默认值播种判据改为显式标记
播种判据曾经是「config 表为空」。而发行包的 postinst 先跑 setup.sh → initconfig,后者会写一行 webui.listen_addr,于是**全新安装**被判定为 "已有配置"并整体跳过播种:没有 core.plugin.dir(装完 0 个插件)、没有 core.memory.* 路径、也没有随包模型对应的多模态 provider——754MB 产物与 24MB 运行库全成死重量。同样的机制此前已在协议 2 迁移演练里被观察到。 也不能改成"每次都补缺键":老安装升级时被注进新默认值,会让它突然去加载 一个 1.8GB 的模型,那是刻意要避免的静默变重。 故改为显式标记 core.internal.seed_version: 有标记 → 已播种,返回 无标记但有 core.daemon.data_dir → 老安装,只补标记、不播种 两者都没有 → 全新安装,播种并打标记 测试:TestSeedDefaultsAfterInitconfigPrepopulate(精确复现 initconfig 的 那一行写入)、TestSeedDefaultsDoesNotInjectIntoLegacyInstall。
This commit is contained in:
@ -482,9 +482,30 @@ func (r *ConfigRegistry) SeedDefaults(dataDir string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *ConfigRegistry) seedDBValues(dataDir string) {
|
func (r *ConfigRegistry) seedDBValues(dataDir string) {
|
||||||
var count int
|
// 新鲜度判据不能是「config 表非空」。
|
||||||
r.db.QueryRow(`SELECT COUNT(*) FROM config`).Scan(&count)
|
//
|
||||||
if count > 0 {
|
// 发行包的 postinst 会先跑 setup.sh → initconfig,而 initconfig 会写一行
|
||||||
|
// webui.listen_addr。于是**全新安装**的 DB 看上去"已经有内容",整个默认值
|
||||||
|
// 播种被跳过:core.plugin.dir、core.memory.*、多模态 provider 一个都没写。
|
||||||
|
// 现场表现是装完 0 个插件、随包的模型与运行库成死重量。
|
||||||
|
//
|
||||||
|
// 也不能改成"每次都补缺键":老安装升级时被注进新默认值,会让它突然
|
||||||
|
// 去加载一个 1.8GB 的模型——那是刻意要避免的行为(静默变重)。
|
||||||
|
//
|
||||||
|
// 故用显式标记区分三种情形:
|
||||||
|
// 有标记 → 已经播过种,直接返回
|
||||||
|
// 无标记但有 core.daemon.data_dir → 老安装(本键历来由播种写入),
|
||||||
|
// 只补标记、不播种
|
||||||
|
// 两者都没有 → 全新安装,播种并打标记
|
||||||
|
const markerKey = "core.internal.seed_version"
|
||||||
|
var hasMarker, hasLegacy int
|
||||||
|
r.db.QueryRow(`SELECT COUNT(*) FROM config WHERE key = ?`, markerKey).Scan(&hasMarker)
|
||||||
|
if hasMarker > 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.db.QueryRow(`SELECT COUNT(*) FROM config WHERE key = 'core.daemon.data_dir'`).Scan(&hasLegacy)
|
||||||
|
if hasLegacy > 0 {
|
||||||
|
r.db.Exec(`INSERT OR IGNORE INTO config (key, value) VALUES (?, ?)`, markerKey, "1")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -604,6 +625,8 @@ WebUI 概览页展示你的立绘,可通过 /mascot.webp 直接访问。如输
|
|||||||
set("core.input_processing.audio.fallback_model", "")
|
set("core.input_processing.audio.fallback_model", "")
|
||||||
set("core.input_processing.audio.describe_prompt", "请转写这段音频的内容。")
|
set("core.input_processing.audio.describe_prompt", "请转写这段音频的内容。")
|
||||||
|
|
||||||
|
set(markerKey, "1")
|
||||||
|
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -188,6 +188,65 @@ func TestSeedDefaultsToConfig(t *testing.T) {
|
|||||||
r.Close()
|
r.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 发行包全新安装:postinst 先跑 setup.sh → initconfig,而 initconfig 只写
|
||||||
|
// webui.listen_addr。于是 config 表已经非空,旧实现据此判定“已有配置”并整体
|
||||||
|
// 跳过播种——装完没有 core.plugin.dir(0 个插件)、也没有随包模型对应的
|
||||||
|
// 多模态 provider(754MB 产物 + 24MB 运行库全成死重量)。
|
||||||
|
func TestSeedDefaultsAfterInitconfigPrepopulate(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
path := filepath.Join(dir, "config.db")
|
||||||
|
|
||||||
|
r := NewConfigRegistry(path)
|
||||||
|
// 精确复现 initconfig 的唯一一笔写入
|
||||||
|
if _, err := r.db.Exec(`INSERT INTO config (key, value) VALUES ('webui.listen_addr', ':8080')`); err != nil {
|
||||||
|
t.Fatalf("预置 initconfig 行: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.SeedDefaults(dir)
|
||||||
|
|
||||||
|
for _, k := range []string{"core.daemon.data_dir", "core.plugin.dir", "core.memory.multimodal_space.provider"} {
|
||||||
|
if r.GetString(k, "") == "" {
|
||||||
|
t.Fatalf("全新安装(initconfig 已写 webui.listen_addr)后 %s 仍为空:默认值播种被跳过", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if got := r.GetString("core.memory.multimodal_space.provider", ""); got != "chineseclip" {
|
||||||
|
t.Fatalf("随包默认 provider 应为 chineseclip,实为 %q", got)
|
||||||
|
}
|
||||||
|
r.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 老安装升级:绝不能因为新版本加了默认值就把它注进现有 DB——那会让升级即
|
||||||
|
// 静默加载一个 1.8GB 的模型。判据是 core.daemon.data_dir 在场(老安装由播种
|
||||||
|
// 写入)而 seed 标记缺失。
|
||||||
|
func TestSeedDefaultsDoesNotInjectIntoLegacyInstall(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
path := filepath.Join(dir, "config.db")
|
||||||
|
|
||||||
|
r := NewConfigRegistry(path)
|
||||||
|
if _, err := r.db.Exec(`INSERT INTO config (key, value) VALUES ('core.daemon.data_dir', ?)`, dir); err != nil {
|
||||||
|
t.Fatalf("预置老安装行: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.SeedDefaults(dir)
|
||||||
|
|
||||||
|
if got := r.GetString("core.memory.multimodal_space.provider", ""); got != "" {
|
||||||
|
t.Fatalf("老安装升级被注入新默认值 provider=%q(升级后会静默加载大模型)", got)
|
||||||
|
}
|
||||||
|
if got := r.GetString("core.plugin.dir", ""); got != "" {
|
||||||
|
t.Fatalf("老安装升级被注入新默认值 core.plugin.dir=%q", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 但标记必须补上,否则每次启动都会重走判断
|
||||||
|
var n int
|
||||||
|
if err := r.db.QueryRow(`SELECT COUNT(*) FROM config WHERE key = 'core.internal.seed_version'`).Scan(&n); err != nil {
|
||||||
|
t.Fatalf("查 seed 标记: %v", err)
|
||||||
|
}
|
||||||
|
if n != 1 {
|
||||||
|
t.Fatalf("老安装应补上 seed 标记,实际 count=%d", n)
|
||||||
|
}
|
||||||
|
r.Close()
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetHelpers(t *testing.T) {
|
func TestGetHelpers(t *testing.T) {
|
||||||
r := NewConfigRegistry("")
|
r := NewConfigRegistry("")
|
||||||
r.Set("str_key", "hello")
|
r.Set("str_key", "hello")
|
||||||
|
|||||||
Reference in New Issue
Block a user