fix: 平台消息身份传递 — AI-Core 收到正确昵称而非永远 fallback 到管理员
- forwardToAICore 新增 nickname 字段,格式 "昵称 (QQ号)" 明确标识发送者 - 解决非管理员用户 @昔涟 时 AI 仍认为是管理员的身份污染问题 - 同时包含:管理员群聊插入抑制、markdown 粗体剥离、SearXNG 容器、ethend 窗口隐藏 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -84,7 +84,7 @@ func main() {
|
||||
|
||||
// Routing decisions.
|
||||
isAdmin := mapper.IsAdmin(msg.Platform, msg.OriginalSenderUID)
|
||||
isMentioned, mentionReason := detectAdminMention(msg, mapper, cfg)
|
||||
isMentioned, _ := detectAdminMention(msg, mapper, cfg)
|
||||
isBotMentioned := msg.BotUID != "" && containsString(msg.Mentions, msg.BotUID)
|
||||
isSilent := cfg.PlatformSilentEnabled && !isAdmin && !isBotMentioned
|
||||
|
||||
@@ -113,7 +113,6 @@ func main() {
|
||||
|
||||
// Extract image URLs for vision/OCR processing (admin + bot-mentioned + admin-mentioned only).
|
||||
imageURLs := getImageURLs(msg)
|
||||
includeImages := isAdmin || isBotMentioned || isMentioned
|
||||
|
||||
// For group chats, use a channel-based user ID to share context between admin and regular users.
|
||||
chatUserID := msg.SenderID
|
||||
@@ -123,6 +122,11 @@ func main() {
|
||||
groupSessionID := fmt.Sprintf("platform_%s_%s", msg.Platform, msg.ChannelID)
|
||||
|
||||
switch {
|
||||
case isAdmin && !isBotMentioned && shouldAdminBeSilent(msg, router):
|
||||
msg.RouteType = "silent"
|
||||
namespace := buildMemoryNamespace(msg.Platform, msg.ChannelType, msg.ChannelID)
|
||||
response, routeErr = forwardToAICore(cfg, msg, "platform_silent", namespace, namespace, nil)
|
||||
|
||||
case isAdmin:
|
||||
msg.RouteType = "normal"
|
||||
response, routeErr = forwardToAICore(cfg, msg, "text", chatUserID, groupSessionID, imageURLs)
|
||||
@@ -132,19 +136,11 @@ func main() {
|
||||
response, routeErr = forwardToAICore(cfg, msg, "text", chatUserID, groupSessionID, imageURLs)
|
||||
|
||||
case isMentioned:
|
||||
msg.RouteType = "admin_mention"
|
||||
enhancedContent := fmt.Sprintf(
|
||||
"[来自%s平台 %s 频道 %s 的用户 %s 说]\n%s\n\n[系统提示:此消息提及了管理员(原因:%s)。请参考以上消息内容判断是否需要关注。]",
|
||||
msg.Platform, msg.ChannelType, msg.ChannelID, msg.SenderName, msg.Content, mentionReason,
|
||||
)
|
||||
originalContent := msg.Content
|
||||
msg.Content = enhancedContent
|
||||
if includeImages {
|
||||
response, routeErr = forwardToAICore(cfg, msg, "text", "admin", "admin-session-main", imageURLs)
|
||||
} else {
|
||||
response, routeErr = forwardToAICore(cfg, msg, "text", "admin", "admin-session-main", nil)
|
||||
}
|
||||
msg.Content = originalContent
|
||||
// Non-admin user mentioned an admin. Don't respond in channel —
|
||||
// the admin already gets QQ's native @notification. Observe silently.
|
||||
msg.RouteType = "silent"
|
||||
namespace := buildMemoryNamespace(msg.Platform, msg.ChannelType, msg.ChannelID)
|
||||
response, routeErr = forwardToAICore(cfg, msg, "platform_silent", namespace, namespace, nil)
|
||||
|
||||
case isSilent:
|
||||
msg.RouteType = "silent"
|
||||
@@ -191,7 +187,7 @@ func main() {
|
||||
Direction: "outgoing",
|
||||
Platform: msg.Platform,
|
||||
ChannelID: msg.ChannelID,
|
||||
SenderID: msg.OriginalSenderUID,
|
||||
SenderID: msg.BotUID,
|
||||
SenderName: "Cyrene",
|
||||
Content: rm.Content,
|
||||
ContentType: "text",
|
||||
@@ -493,6 +489,31 @@ func containsString(list []string, val string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// shouldAdminBeSilent checks if admin is talking to other users in a group.
|
||||
// Returns true if 昔涟 should not interrupt (route as silent observation instead).
|
||||
func shouldAdminBeSilent(msg *bridge.UnifiedMessage, router *bridge.PlatformRouter) bool {
|
||||
if msg.ChannelType != "group" {
|
||||
return false
|
||||
}
|
||||
// Rule 1: Admin @mentions someone other than the bot → talking to them, don't interrupt.
|
||||
for _, m := range msg.Mentions {
|
||||
if m != msg.BotUID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// Rule 2: Recent context shows a conversation with non-admin users.
|
||||
// Note: updateContext runs before this handler, so RecentSenders already
|
||||
// includes the current message. Check the second-to-last sender instead.
|
||||
ctx := router.GetContext(msg.Platform, msg.ChannelID)
|
||||
if ctx != nil && len(ctx.RecentSenders) >= 2 {
|
||||
prevSender := ctx.RecentSenders[len(ctx.RecentSenders)-2]
|
||||
if prevSender != msg.OriginalSenderUID && prevSender != msg.BotUID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// getImageURLs extracts image attachment URLs from a UnifiedMessage.
|
||||
func getImageURLs(msg *bridge.UnifiedMessage) []string {
|
||||
if len(msg.Attachments) == 0 {
|
||||
@@ -516,6 +537,7 @@ func forwardToAICore(cfg *config.Config, msg *bridge.UnifiedMessage, mode, userI
|
||||
"message": msg.Content,
|
||||
"mode": mode,
|
||||
"routing": msg.RouteType,
|
||||
"nickname": fmt.Sprintf("%s (%s)", msg.SenderName, msg.OriginalSenderUID),
|
||||
"source": map[string]string{
|
||||
"platform": msg.Platform,
|
||||
"channel_id": msg.ChannelID,
|
||||
|
||||
Reference in New Issue
Block a user