feat: 同平台多账号支持 — adapter_name 贯穿全链路
- UnifiedMessage 新增 AdapterName 字段 - router 从适配器 ConfigName() 捕获 adapter 实例名 - forwardToAICore source 新增 adapter_name - ai-core SetBotUID key 优先用 adapter_name,回退 platform - 更新优化大纲加入 P4.1 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -871,7 +871,8 @@ func handleChat(
|
|||||||
SenderName string `json:"sender_name"`
|
SenderName string `json:"sender_name"`
|
||||||
OriginalUID string `json:"original_uid"`
|
OriginalUID string `json:"original_uid"`
|
||||||
BotUID string `json:"bot_uid"`
|
BotUID string `json:"bot_uid"`
|
||||||
GroupName string `json:"group_name,omitempty"`
|
GroupName string
|
||||||
|
AdapterName string `json:"group_name,omitempty"`
|
||||||
} `json:"source,omitempty"`
|
} `json:"source,omitempty"`
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
@@ -888,9 +889,18 @@ func handleChat(
|
|||||||
if thinker != nil {
|
if thinker != nil {
|
||||||
thinker.RecordUserMessage(req.SessionID)
|
thinker.RecordUserMessage(req.SessionID)
|
||||||
if req.Source.Platform != "" && req.Source.BotUID != "" {
|
if req.Source.Platform != "" && req.Source.BotUID != "" {
|
||||||
thinker.SetBotUID(req.Source.Platform, req.Source.BotUID)
|
adapterKey := req.Source.Platform
|
||||||
|
if req.Source.AdapterName != "" {
|
||||||
|
adapterKey = req.Source.AdapterName
|
||||||
|
}
|
||||||
|
thinker.SetBotUID(adapterKey, req.Source.BotUID)
|
||||||
}
|
}
|
||||||
if req.Source.Platform != "" && req.Source.ChannelID != "" {
|
if req.Source.Platform != "" && req.Source.ChannelID != "" {
|
||||||
|
adapterKey := req.Source.Platform
|
||||||
|
if req.Source.AdapterName != "" {
|
||||||
|
adapterKey = req.Source.AdapterName
|
||||||
|
}
|
||||||
|
thinker.SetBotUID(adapterKey, req.Source.BotUID)
|
||||||
thinker.AddOrUpdatePlatformChannel(req.Source.Platform, req.Source.ChannelType, req.Source.ChannelID, req.Source.GroupName)
|
thinker.AddOrUpdatePlatformChannel(req.Source.Platform, req.Source.ChannelType, req.Source.ChannelID, req.Source.GroupName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -924,7 +934,11 @@ func handleChat(
|
|||||||
if thinker != nil {
|
if thinker != nil {
|
||||||
thinker.RecordUserMessage(req.SessionID)
|
thinker.RecordUserMessage(req.SessionID)
|
||||||
if req.Source.Platform != "" && req.Source.BotUID != "" {
|
if req.Source.Platform != "" && req.Source.BotUID != "" {
|
||||||
thinker.SetBotUID(req.Source.Platform, req.Source.BotUID)
|
adapterKey := req.Source.Platform
|
||||||
|
if req.Source.AdapterName != "" {
|
||||||
|
adapterKey = req.Source.AdapterName
|
||||||
|
}
|
||||||
|
thinker.SetBotUID(adapterKey, req.Source.BotUID)
|
||||||
}
|
}
|
||||||
if req.Source.Platform != "" && req.Source.ChannelID != "" {
|
if req.Source.Platform != "" && req.Source.ChannelID != "" {
|
||||||
thinker.AddOrUpdatePlatformChannel(req.Source.Platform, req.Source.ChannelType, req.Source.ChannelID, req.Source.GroupName)
|
thinker.AddOrUpdatePlatformChannel(req.Source.Platform, req.Source.ChannelType, req.Source.ChannelID, req.Source.GroupName)
|
||||||
|
|||||||
@@ -665,6 +665,7 @@ func forwardToAICore(cfg *config.Config, msg *bridge.UnifiedMessage, mode, userI
|
|||||||
"original_uid": msg.OriginalSenderUID,
|
"original_uid": msg.OriginalSenderUID,
|
||||||
"bot_uid": msg.BotUID,
|
"bot_uid": msg.BotUID,
|
||||||
"group_name": msg.GroupName,
|
"group_name": msg.GroupName,
|
||||||
|
"adapter_name": msg.AdapterName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if len(images) > 0 {
|
if len(images) > 0 {
|
||||||
|
|||||||
@@ -150,6 +150,11 @@ func (r *PlatformRouter) RouteMessage(adapterKey string, rawMsg interface{}) (*U
|
|||||||
unified.BotUID = selfAware.SelfID()
|
unified.BotUID = selfAware.SelfID()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Capture adapter config name for multi-account routing.
|
||||||
|
if named, ok := a.(interface{ ConfigName() string }); ok {
|
||||||
|
unified.AdapterName = named.ConfigName()
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve identity (nil for unknown users; caller decides routing).
|
// Resolve identity (nil for unknown users; caller decides routing).
|
||||||
// Use platform type (e.g. "qq") for identity resolution, not adapter key.
|
// Use platform type (e.g. "qq") for identity resolution, not adapter key.
|
||||||
identity := r.mapper.ResolveOrNil(a.PlatformName(), unified.SenderID)
|
identity := r.mapper.ResolveOrNil(a.PlatformName(), unified.SenderID)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type UnifiedMessage struct {
|
|||||||
GroupName string `json:"group_name,omitempty"` // resolved group name for group chats
|
GroupName string `json:"group_name,omitempty"` // resolved group name for group chats
|
||||||
OriginalRawMessage interface{} `json:"-"` // preserved for SendMessage wiring
|
OriginalRawMessage interface{} `json:"-"` // preserved for SendMessage wiring
|
||||||
BotUID string `json:"-"` // bot's own platform UID, set by router
|
BotUID string `json:"-"` // bot's own platform UID, set by router
|
||||||
|
AdapterName string `json:"-"` // adapter config name (e.g. "qq-main"), set by router
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attachment represents a file/image/voice/video attachment.
|
// Attachment represents a file/image/voice/video attachment.
|
||||||
|
|||||||
@@ -181,6 +181,42 @@ QQ 平台标识(`【QQ群聊:xxx】`、`【QQ私聊:xxx】`)硬编码在 `th
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### 5.1 P4.1 — 同平台多账号支持
|
||||||
|
|
||||||
|
#### 现状
|
||||||
|
|
||||||
|
Platform-Bridge 已支持同一平台注册多个 adapter 实例(如 `qq-main`, `qq-secondary`),但 ai-core 侧的 key 系统用 platform 类型字符串(`"qq"`)而非 adapter config name:
|
||||||
|
|
||||||
|
| 位置 | 当前 key | 问题 |
|
||||||
|
|---|---|---|
|
||||||
|
| `botUIDs` | `"qq"` → UID | 多个 OBv11 账号只能存一个 UID |
|
||||||
|
| `ProactiveTarget.Platform` | `"qq"` | 主动消息不知道发给哪个 adapter |
|
||||||
|
| `platform_qq_xxx` session ID | `"qq"` | ✅ 正确,同群聊多账号应共享上下文 |
|
||||||
|
|
||||||
|
#### 目标
|
||||||
|
|
||||||
|
将 ai-core 内部的 platform 标识从"协议类型"改为"adapter 实例名",使多个同平台账号独立工作。
|
||||||
|
|
||||||
|
#### 要点
|
||||||
|
|
||||||
|
- **platform-bridge `forwardToAICore`**:source.platform 传 adapter config name(`"qq-main"`)而非 `"qq"`
|
||||||
|
- **ai-core `SetBotUID`**:key 改为 adapter name,允许多个同平台 Bot
|
||||||
|
- **`ProactiveTarget.Platform`**:传 adapter name,platform-bridge 直接用它查 router
|
||||||
|
- **platform-bridge `sendProactive` handler**:直接用 platform 字段作为 adapter name
|
||||||
|
- **`PlatformFormat` 注册表**:key 保持 platform 类型(`"qq"`),格式与协议绑定,不绑定账号
|
||||||
|
- **session ID prefix**:保持 `platform_qq_`,同群聊多账号共享上下文
|
||||||
|
|
||||||
|
#### 涉及文件
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|---|---|
|
||||||
|
| `platform-bridge/cmd/main.go` | forwardToAICore 传 adapter name |
|
||||||
|
| `platform-bridge/internal/handler/bridge_handler.go` | sendProactive 直接用 platform 查 adapter |
|
||||||
|
| `ai-core/cmd/main.go` | SetBotUID key 用 adapter name |
|
||||||
|
| `ai-core/background/thinker.go` | ProactiveTarget + botUIDs 适配 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 6. P5 — 工具子会话增强
|
## 6. P5 — 工具子会话增强
|
||||||
|
|
||||||
### 6.1 子会话返回时间戳
|
### 6.1 子会话返回时间戳
|
||||||
@@ -204,17 +240,18 @@ QQ 平台标识(`【QQ群聊:xxx】`、`【QQ私聊:xxx】`)硬编码在 `th
|
|||||||
## 7. 实施顺序建议
|
## 7. 实施顺序建议
|
||||||
|
|
||||||
```
|
```
|
||||||
Phase A (本节可做) ─────────────────────────────
|
Phase A (本节可做) ───────────────────────────── ✅ 已完成
|
||||||
P2.2 对话后思考可追加 ~10 行改动
|
P2.2 对话后思考可追加 ~10 行改动
|
||||||
P2.1 自主思考后触发记忆整理 ~5 行改动
|
P2.1 自主思考后触发记忆整理 ~5 行改动
|
||||||
P5.1 子会话返回时间戳 ~20 行改动
|
P5.1 子会话返回时间戳 ~20 行改动
|
||||||
|
|
||||||
Phase B (需要跨服务协调) ───────────────────────
|
Phase B (需要跨服务协调) ─────────────────────── ✅ 已完成
|
||||||
P1 LLM 可自主操作提醒与日程 新建 1 文件 + 注册工具
|
P1 LLM 可自主操作提醒与日程 新建 1 文件 + 注册工具
|
||||||
P0 自主思考分层 重构 thinker 核心循环
|
P0 自主思考分层 重构 thinker 核心循环
|
||||||
|
|
||||||
Phase C (架构级改动) ───────────────────────────
|
Phase C (架构级改动) ───────────────────────────
|
||||||
P4 多平台前缀统一抽象 跨 ai-core + platform-bridge
|
P4 QQ→OBv11 重命名 + PlatformFormat 抽象 ✅ 已完成
|
||||||
|
P4.1 同平台多账号支持 跨 ai-core + platform-bridge ← 当前
|
||||||
P3 群聊并发(协会议话) 跨 ai-core + platform-bridge
|
P3 群聊并发(协会议话) 跨 ai-core + platform-bridge
|
||||||
|
|
||||||
Phase D (后续优化) ─────────────────────────────
|
Phase D (后续优化) ─────────────────────────────
|
||||||
|
|||||||
Reference in New Issue
Block a user