feat: 添加物流查询功能和完善 token 传递

- 添加 get_logistics 工具查询 Mall API /mall/api/order/parcel
- 修复 Cookie token 传递到 MCP 的问题
- 增强 LLM 客户端超时处理和日志
- 移除 MALL_API_TOKEN,使用用户登录 token
- 更新测试页面使用 setUser 设置用户属性
- 增强 webhook 调试日志
This commit is contained in:
wangliang
2026-01-16 18:36:17 +08:00
parent cd787d608b
commit c4e97cf312
9 changed files with 334 additions and 111 deletions

View File

@@ -136,6 +136,26 @@ async def handle_incoming_message(payload: ChatwootWebhookPayload, cookie_token:
contact = payload.contact or payload.sender
user_id = str(contact.id) if contact else "unknown"
# Log webhook payload structure for debugging
logger.info(
"Webhook payload structure",
payload_event=payload.event,
has_conversation=bool(conversation),
has_contact=bool(contact),
contact_type=type(contact).__name__ if contact else None,
conversation_id=conversation_id
)
# Log full payload keys for debugging
payload_dict = payload.model_dump()
logger.info(
"Full webhook payload keys",
keys=list(payload_dict.keys()),
conversation_keys=list(payload_dict.get('conversation', {}).keys()) if payload_dict.get('conversation') else [],
contact_keys=list(payload_dict.get('contact', {}).keys()) if payload_dict.get('contact') else [],
sender_keys=list(payload_dict.get('sender', {}).keys()) if payload_dict.get('sender') else []
)
# Get account_id from payload (top-level account object)
# Chatwoot webhook includes account info at the top level
account_obj = payload.account
@@ -148,13 +168,35 @@ async def handle_incoming_message(payload: ChatwootWebhookPayload, cookie_token:
if not user_token:
# 1. 尝试从 contact/custom_attributes 获取
if contact:
contact_dict = contact.model_dump() if hasattr(contact, 'model_dump') else contact.__dict__
user_token = TokenManager.extract_token_from_contact(contact_dict)
logger.debug("Extracted token from contact", has_token=bool(user_token))
logger.info(
"Checking contact for token",
contact_id=contact.id if contact else None,
contact_type=type(contact).__name__
)
# 只有 WebhookContact 才有 custom_attributes
if hasattr(contact, 'custom_attributes'):
logger.info(
"Checking contact custom_attributes",
has_custom_attributes=bool(contact.custom_attributes)
)
custom_attrs = contact.custom_attributes or {}
logger.info(
"Contact custom_attributes",
keys=list(custom_attrs.keys()) if custom_attrs else [],
has_jwt_token='jwt_token' in custom_attrs if custom_attrs else False,
has_mall_token='mall_token' in custom_attrs if custom_attrs else False
)
contact_dict = {"custom_attributes": custom_attrs}
user_token = TokenManager.extract_token_from_contact(contact_dict)
logger.debug("Extracted token from contact", has_token=bool(user_token))
else:
logger.debug("Contact type is WebhookSender, no custom_attributes available")
# 2. 尝试从 conversation.meta.sender.custom_attributes 获取Chatwoot SDK setUser 设置的位置)
if not user_token and conversation:
# 记录 conversation 的类型和内容用于调试
logger.debug("Conversation object type", type=str(type(conversation)))
if hasattr(conversation, 'model_dump'):
conv_dict = conversation.model_dump()
@@ -162,12 +204,32 @@ async def handle_incoming_message(payload: ChatwootWebhookPayload, cookie_token:
logger.debug("Has meta", has_meta='meta' in conv_dict)
meta_sender = conv_dict.get('meta', {}).get('sender', {})
logger.info(
"Conversation meta.sender",
has_sender=bool(meta_sender),
sender_keys=list(meta_sender.keys()) if meta_sender else [],
has_custom_attributes=bool(meta_sender.get('custom_attributes')) if meta_sender else False
)
if meta_sender.get('custom_attributes'):
logger.info("Found custom_attributes in meta.sender", keys=list(meta_sender['custom_attributes'].keys()))
user_token = TokenManager.extract_token_from_contact({'custom_attributes': meta_sender['custom_attributes']})
logger.info("Token found in conversation.meta.sender.custom_attributes", token_prefix=user_token[:20] if user_token else None)
if user_token:
logger.info("JWT token found", user_id=user_id, source="cookie" if cookie_token else "contact")
logger.info(
"JWT token found",
user_id=user_id,
source="cookie" if cookie_token else "contact",
token_prefix=user_token[:20] if user_token else None
)
else:
logger.warning(
"No JWT token found from any source",
user_id=user_id,
cookie_token_exists=bool(cookie_token),
contact_type=type(contact).__name__ if contact else None
)
logger.info(
"Processing incoming message",
@@ -352,7 +414,9 @@ async def chatwoot_webhook(
# 尝试从请求 Cookie 中获取用户 Token
user_token = request.cookies.get("token") # 从 Cookie 读取 token
if user_token:
logger.info("User token found in request cookies")
logger.info("User token found in request cookies", token_prefix=user_token[:20])
else:
logger.debug("No token found in request cookies (this is expected for webhook requests)")
# Verify signature
signature = request.headers.get("X-Chatwoot-Signature", "")