fix: 死锁修复、管理员权限集中管控、群聊频率控制、表情映射修复
thinker.go: 移除所有 defer t.muUnlock() 持锁跨阻塞调用的模式,消除8处死锁点 - performThink: defer→立即解锁,LLM调用不再持锁 - lightThinkLoop: defer在for循环内→第2次迭代自死锁 - resetSilenceTimer: defer持锁调performThink - UpdatePresence: defer持锁调time.Sleep+performThink - storeThought: defer+panic→锁泄露; 移除extractProactiveMessage嵌套锁 is_admin三层防御: - synthesizer: 系统提示词注入管理员/非管理员身份标签 - iot_provider: 非管理员直接拒绝IoT操作 - plugin-manager: ToolDefinition.AdminOnly自动拦截,集中管控 群聊优化: - group_ambient: 强化审查指令,【不发送】自审查标签 - 群聊间隔4s→3s,最多2条/轮 - 工具失败也推跟进消息,避免沉默 平台桥接: - 日志文件名使用适配器唯一标识符(ConfigName) - QQ表情映射替换为官方116条目数据 - CQ表情保留名称/ID
This commit is contained in:
@@ -162,6 +162,7 @@ type ProcessParams struct {
|
||||
ChannelID string // platform channel ID (group ID or private OBv11 number)
|
||||
BotUID string // bot's own platform UID (e.g., OBv11 account)
|
||||
AdapterName string // adapter config name for routing
|
||||
IsAdmin bool // 发送者是否为管理员
|
||||
}
|
||||
|
||||
// ProcessResult 处理结果
|
||||
@@ -384,6 +385,7 @@ func (o *Orchestrator) ProcessInput(
|
||||
PersonaConfig: personaConfig,
|
||||
Intent: intent,
|
||||
Nickname: userName,
|
||||
IsAdmin: params.IsAdmin,
|
||||
}
|
||||
|
||||
// 只有明确的关键词问候才跳过子会话分派,日常闲聊也需要检索记忆
|
||||
@@ -455,6 +457,7 @@ func (o *Orchestrator) ProcessInput(
|
||||
ChannelType: params.ChannelType,
|
||||
ChannelID: params.ChannelID,
|
||||
AdapterName: params.AdapterName,
|
||||
IsAdmin: params.IsAdmin,
|
||||
}
|
||||
if prevEnrichment != nil {
|
||||
synthParams.MemorySummary = prevEnrichment.MemorySummary
|
||||
|
||||
@@ -61,6 +61,7 @@ type SynthesizeParams struct {
|
||||
ChannelType string // direct / group
|
||||
ChannelID string // platform channel ID
|
||||
AdapterName string // adapter config name
|
||||
IsAdmin bool // 发送者是否为管理员
|
||||
}
|
||||
|
||||
// Synthesize 综合所有子会话结果,流式生成最终回复。
|
||||
@@ -217,8 +218,8 @@ func (s *Synthesizer) executeAsyncAndStore(tc model.ToolCall, args map[string]in
|
||||
Success: result != nil && result.Success,
|
||||
})
|
||||
}
|
||||
// 触发工具跟进回调 — 由 main.go 驱动 LLM 生成回复并推送到原渠道
|
||||
if s.resultPusher != nil && result != nil && result.Success {
|
||||
// 触发工具跟进回调 — 成功或失败都推送,避免用户一直等待
|
||||
if s.resultPusher != nil && result != nil {
|
||||
s.resultPusher(params.SessionID, params.UserID, tc.Name, string(resultJSON), params)
|
||||
}
|
||||
}
|
||||
@@ -249,7 +250,22 @@ func (s *Synthesizer) buildSynthesizeMessages(params SynthesizeParams) []model.L
|
||||
if params.ChannelType == "group" {
|
||||
messages = append(messages, model.LLMMessage{
|
||||
Role: model.RoleSystem,
|
||||
Content: "【群聊上下文】这条消息来自OBv11群聊。消息前缀 [群聊 群号] 昵称 (OBv11账号) 标注了真实发送者。你不是在和开拓者一对一私聊,而是在群聊中和不同成员交流。请根据当前这条消息前缀中的发送者名字来称呼对方——即使你之前在历史对话中称呼过别人,也不要把之前用的称呼套在当前发送者身上。不同的人有不同的名字。只在对你说话或延续已有对话时才回复。",
|
||||
Content: "【群聊规则 — 必须严格遵守】\n1. 这是群聊,你正在和多人同时交流。只在有人@你、叫你名字、或话题直接涉及你时才回复。\n2. 每次回复最多1-2句话,不要长篇大论,不要连发多条消息。\n3. 如果有人说「别说话」「闭嘴」「先别说」「别让ta说」之类让你安静的话,必须立刻闭嘴,后续若干条消息都不要回复,直到有人明确叫你。\n4. 消息前缀 [群聊 群号] 昵称 (OBv11账号) 标注了真实发送者,请用当前发送者的名字称呼对方,不要混用之前对话中别人的称呼。",
|
||||
})
|
||||
}
|
||||
|
||||
// 管理员身份识别:明确告知昔涟当前发送者是否为管理员。
|
||||
// 非管理员不能操作关键功能(设备控制、系统管理等)。
|
||||
// 昔涟应自主判断:对管理员的指令正常执行;对非管理员的越权请求温柔拒绝。
|
||||
if params.IsAdmin {
|
||||
messages = append(messages, model.LLMMessage{
|
||||
Role: model.RoleSystem,
|
||||
Content: "【管理员身份】当前与你对话的是管理员(开拓者本人)。他拥有设备控制、系统管理等全部权限。请以面对开拓者本人的态度正常回应他的所有指令。",
|
||||
})
|
||||
} else if params.ChannelType == "group" {
|
||||
messages = append(messages, model.LLMMessage{
|
||||
Role: model.RoleSystem,
|
||||
Content: "【非管理员】当前发送者不是管理员。如果对方要求你控制设备、修改系统配置、或执行涉及隐私/安全的操作,请用你自然俏皮的语气温柔地拒绝——可以说「只有开拓者才能让人家做这些事呢~」之类的话。不要机械地说「你没有权限」,而是像朋友间开玩笑一样自然地带过。如果对方只是闲聊、问问题、分享心情,则正常回应即可。",
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user