feat(engage): 群聊自主参与度引擎核心(design/18 P2a+P2b)
- persona 加 triggerWords(昔涟/Cyrene/有瑕的追忆/追忆);Loader 解析 - light.go: shouldRespond 拆分 legacy 与 engage 路径;LightInput/LightDecision 扩展 - engage.go(新): EngageConfig + IDLE/PROBING/ACTIVE/COOLDOWN 状态机(按 platform:groupID 内存) + 概率触发(可注入rand) + 角色名提词触发 + 活动期跟随(话题转移/连续无感/窗口) + 负面态度冷避 - engagejudge.go(新): NewLLMLightJudge,一次成本受控轻LLM判 值不值得回(不判身份), 解析失败/超时 fail-closed 静默 - channelbridge.go: Options(TriggerWords/PersonaPrompt/Engage/EngageFor/EngageRand) + 字段初始化 - wire.go: 接线 Light+TriggerWords+PersonaPrompt+Engage(默认概率0.10) - 红线: 未触发/未命中概率绝不调LLM; 身份靠actor元数据; 敏感不落日志; 零新依赖 - 测试: engage_test.go(触发/状态机/冷避/成本受控/JUDGE输入) + persona triggerWords 用例 - 验收: go build/vet/test ./... 全绿
This commit is contained in:
1 parent
2d7a377d74
commit
8eaf81bd0d
9 files changed
+1156
-13
No files matched your search
@@ -86,6 +86,11 @@ type Persona struct {
|
||||
Emotion EmotionParams `yaml:"emotion"`
|
||||
Affection AffectionParams `yaml:"affection"`
|
||||
Visual PersonaVisual `yaml:"visual,omitempty"`
|
||||
// TriggerWords are the role-name words that, when a public-platform group
|
||||
// message mentions one, route the message into the participation PROBING
|
||||
// stage even without a direct @ (design/18 §2 触发②). Each persona defines its
|
||||
// own reminder words; they never imply identity (that stays structural).
|
||||
TriggerWords []string `yaml:"triggerWords,omitempty"`
|
||||
}
|
||||
|
||||
// EmotionConfig converts this persona's own fields into the params consumed by
|
||||
|
||||
@@ -79,6 +79,24 @@ func TestLoad_ValidYAML(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoad_TriggerWords(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// A persona without triggerWords yields an empty slice; with them, the list is
|
||||
// preserved (design/18 §2: per-persona role-name reminder words).
|
||||
yaml := "id: xilian\nname: 昔涟\ncharacterRef: c\nidentity:\n role: r\n systemPrompt: s\n" +
|
||||
"triggerWords:\n - 昔涟\n - Cyrene\n - 有瑕的追忆\n"
|
||||
path := writeFile(t, t.TempDir(), "xilian.yaml", yaml)
|
||||
p, err := Load(path)
|
||||
if err != nil {
|
||||
t.Fatalf("Load() error: %v", err)
|
||||
}
|
||||
if len(p.TriggerWords) != 3 || p.TriggerWords[0] != "昔涟" ||
|
||||
p.TriggerWords[1] != "Cyrene" || p.TriggerWords[2] != "有瑕的追忆" {
|
||||
t.Fatalf("TriggerWords = %v, want [昔涟 Cyrene 有瑕的追忆]", p.TriggerWords)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoad_MissingRequiredFields(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in new issue
Block a user