fix: resolve Feishu cross-app notification routing bug

Implement per-app open_id storage via user_feishu_open_ids table with
union_id-based cross-app user identification. WS handlers now auto-capture
open_id+union_id and resolve/associate user accounts. Schedule notifications
route through the correct bot's open_id instead of always falling back to 苹果.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
renjianbo
2026-05-06 00:36:40 +08:00
parent 3dd098482e
commit f33bc461ff
11 changed files with 503 additions and 24 deletions

View File

@@ -66,6 +66,21 @@ def _get_sender_open_id(data) -> Optional[str]:
return None
def _get_sender_union_id(data) -> Optional[str]:
"""从消息事件中提取发送者 union_id跨应用唯一"""
try:
ev = data.event
sender = getattr(ev, "sender", None)
if not sender:
return None
sender_id = getattr(sender, "sender_id", None)
if not sender_id:
return None
return getattr(sender_id, "union_id", None)
except Exception:
return None
def _get_chat_type(data) -> str:
"""获取聊天类型。"""
try:
@@ -125,6 +140,7 @@ def _make_llm_logger(db, agent_id: Optional[str] = None, user_id: Optional[str]
async def _handle_message_async(data):
"""异步处理橙子消息 — 固定使用橙子助手 Agent。"""
open_id = _get_sender_open_id(data)
union_id = _get_sender_union_id(data)
chat_type = _get_chat_type(data)
text = _get_message_text(data)
@@ -139,11 +155,18 @@ async def _handle_message_async(data):
from sqlalchemy.orm import Session
from app.core.database import SessionLocal
from app.models.agent import Agent
from app.services.feishu_open_id_service import resolve_user_and_save
db: Optional[Session] = None
try:
db = SessionLocal()
# 自动保存/关联此应用的 open_id跨应用识别
resolved_uid = resolve_user_and_save(
db, app_id=settings.ORANGE_APP_ID or "",
open_id=open_id, union_id=union_id,
)
# 固定使用橙子助手 Agent
agent_id = settings.ORANGE_AGENT_ID
if not agent_id:
@@ -199,7 +222,7 @@ async def _handle_message_async(data):
vector_memory_enabled=bool(cfg.get("memory_vector_enabled", True)),
learning_enabled=bool(cfg.get("memory_learning", True)),
),
user_id=None,
user_id=resolved_uid,
memory_scope_id=str(agent.id),
)