Files
HomeAgent/internal/agent/personal_test.go
JianFeeeee 7318a10828 feat(persona): 人格设定配置项化 + 默认模板契约测试 + 腐坏告警
起因(v1.2.0 压测):线上实例内核日志/接口都报 1.2.0,agent 被问版本时却按人格卡
自述 v0.9.0 + C ABI v2(该机制 v1.0.0 已删除)。根因是人格只有「文件」一个来源且无人
维护——写死的版本号必然随发版腐坏。

改动:
1. 新增配置项 core.agent.personal_prompt(多行文本),默认值为内置模板
   config.DefaultPersonaPrompt,随其它默认值同批播种(老安装不注入,语义不变)
2. 默认模板**不含任何版本号字面量**,并显式要求「被问到版本/构建信息时以运行时快照
   (healthcheck_kernel)为准」——从根上消掉这类腐坏
3. 人格来源优先级:personal/personal.md(存在且非空)> 配置项 > 无
   启动日志明确打印来源;文件含腐坏内容(版本号字面量 / 已删除机制的说法)时告警并
   建议迁移到配置项
4. internal/agent.PersonaStaleHints:腐坏检测(版本号正则 + 已删除机制词表)

契约测试(防复发):
- TestDefaultPersonaPromptHasNoVersionLiterals:默认模板不得含 v?\d+\.\d+\.\d+,
  且必须含「运行时快照」要求
- TestPersonaPromptRegisteredWithDefault:注册存在、默认值一致、播种真的写入
- TestPersonaStaleHints:线上人格卡原文必须被识别(v0.9.0 / C ABI v2),干净文本不误报

验证:go build ./cmd/homed ok;go vet 三个包 ok;go test ./internal/config ./internal/agent ok;
端到端两场景(无文件→来源=配置项 1307 字节;有旧文件→来源=文件 + 告警列出 v0.9.0 与 C ABI v2)。
2026-09-12 12:42:43 +08:00

63 lines
2.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package agent
import (
"os"
"path/filepath"
"strings"
"testing"
)
// PersonaStaleHints 必须能认出会腐坏的人格内容——版本号字面量与已删除机制。
func TestPersonaStaleHints(t *testing.T) {
// 现场真实文本(线上人格卡的原文)
stale := "你是 HomeAgent内核代号 HΔ-Kernel当前版本 v0.9.0)。\n当前运行的二进制是 v0.9.0C ABI v2构建于 2026-08-15。"
hints := PersonaStaleHints(stale)
if len(hints) == 0 {
t.Fatal("未识别出写死版本号与 C ABI 的人格文本")
}
joined := strings.Join(hints, " | ")
if !strings.Contains(joined, "版本号字面量") {
t.Fatalf("应报出版本号字面量,实际: %s", joined)
}
if !strings.Contains(joined, "C ABI v2") {
t.Fatalf("应报出已删除机制的残留说法,实际: %s", joined)
}
// 干净文本(配置项默认模板)不应误报
if h := PersonaStaleHints(DefaultPersonaProbeClean()); len(h) != 0 {
t.Fatalf("干净人格被误报: %v", h)
}
}
// DefaultPersonaProbeClean 由 config 包的默认模板等价物构成——
// 这里不复用 config 包以避免 import cycle只断言「不含版本号与旧机制」的文本不被误报。
func DefaultPersonaProbeClean() string {
return "你是 HomeAgent内核代号 HΔ-Kernel。外部插件是独立子进程经 stdio JSON-RPC 通信;" +
"被问到版本时以运行时快照为准。"
}
func TestLoadAndSavePersonality(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "personal", "personal.md")
// 文件不存在时返回空(不报错、不创建)
p, err := LoadPersonality(path)
if err != nil || p == nil || p.Content != "" {
t.Fatalf("缺文件时应返回空人格,实际 %+v err=%v", p, err)
}
if err := SavePersonality(path, "人格内容"); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(path); err != nil {
t.Fatalf("SavePersonality 未落盘: %v", err)
}
p, err = LoadPersonality(path)
if err != nil || p.Content != "人格内容" {
t.Fatalf("读回失败: %+v err=%v", p, err)
}
if got := p.InjectPrompt(); !strings.Contains(got, "【人格设定】") || !strings.Contains(got, "人格内容") {
t.Fatalf("InjectPrompt 形状不对: %q", got)
}
}