mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 00:40:45 +08:00
本次迁移将网关/通道/工具/技能/脚本与协议资源集中到新结构,统一路径常量与脚本转发机制,减少顶层噪音并保证运行与测试行为一致。 Made-with: Cursor
127 lines
4.7 KiB
Python
127 lines
4.7 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
|
|
def _first_non_empty(*values: Any) -> str:
|
|
for v in values:
|
|
s = str(v or "").strip()
|
|
if s:
|
|
return s
|
|
return ""
|
|
|
|
|
|
def _pick(d: dict[str, Any], *keys: str) -> Any:
|
|
for k in keys:
|
|
if k in d:
|
|
return d.get(k)
|
|
return None
|
|
|
|
|
|
def _extract_text(raw: dict[str, Any]) -> str:
|
|
direct_text = _pick(raw, "text")
|
|
if isinstance(direct_text, str) and direct_text.strip():
|
|
return direct_text.strip()
|
|
direct = _first_non_empty(
|
|
_pick(raw, "content", "Content"),
|
|
)
|
|
if direct:
|
|
return direct
|
|
text_obj = raw.get("text")
|
|
if isinstance(text_obj, dict):
|
|
return _first_non_empty(_pick(text_obj, "content", "Content"))
|
|
text_raw_obj = raw.get("text_raw")
|
|
if isinstance(text_raw_obj, dict):
|
|
return _first_non_empty(_pick(text_raw_obj, "content", "Content", "text"))
|
|
content_obj = raw.get("content")
|
|
if isinstance(content_obj, dict):
|
|
return _first_non_empty(_pick(content_obj, "text", "content", "Content"))
|
|
if isinstance(raw.get("msg"), dict):
|
|
return _first_non_empty(_pick(raw.get("msg", {}), "text", "content", "Content"))
|
|
msg_obj = raw.get("message")
|
|
if isinstance(msg_obj, dict):
|
|
return _first_non_empty(
|
|
_pick(msg_obj, "text", "content", "Content"),
|
|
_pick(msg_obj.get("text", {}), "content") if isinstance(msg_obj.get("text"), dict) else None,
|
|
)
|
|
payload = raw.get("payload")
|
|
if isinstance(payload, dict):
|
|
return _first_non_empty(
|
|
_pick(payload, "text", "content", "Content"),
|
|
_pick(payload.get("text", {}), "content") if isinstance(payload.get("text"), dict) else None,
|
|
)
|
|
return ""
|
|
|
|
|
|
def normalize_wecom_event(raw: dict[str, Any]) -> dict[str, Any]:
|
|
"""Convert WeCom-like raw events into normalized gateway payload."""
|
|
chat_id = _first_non_empty(
|
|
_pick(raw, "chat_id", "conversation_id", "conversationId", "chatid", "roomid", "RoomId"),
|
|
_pick(raw.get("message", {}), "chat_id", "conversation_id", "chatid")
|
|
if isinstance(raw.get("message"), dict)
|
|
else None,
|
|
_pick(raw.get("chat", {}), "id", "chat_id", "chatid", "roomid")
|
|
if isinstance(raw.get("chat"), dict)
|
|
else None,
|
|
_pick(raw.get("conversation", {}), "id", "chat_id", "chatid")
|
|
if isinstance(raw.get("conversation"), dict)
|
|
else None,
|
|
_pick(raw.get("room", {}), "id", "roomid", "chatid")
|
|
if isinstance(raw.get("room"), dict)
|
|
else None,
|
|
)
|
|
from_obj = raw.get("from")
|
|
user_id = _first_non_empty(
|
|
_pick(raw, "user_id", "from_user_id", "fromUserId", "FromUserName", "userid", "external_userid"),
|
|
from_obj if isinstance(from_obj, str) else None,
|
|
_pick(from_obj, "userid", "user_id", "id", "from_user_id", "UserId", "userid64", "uid")
|
|
if isinstance(from_obj, dict)
|
|
else None,
|
|
_pick(raw.get("sender", {}), "userid", "user_id", "id") if isinstance(raw.get("sender"), dict) else None,
|
|
_pick(raw.get("message", {}), "from_user_id", "fromUserId") if isinstance(raw.get("message"), dict) else None,
|
|
chat_id,
|
|
)
|
|
if not chat_id:
|
|
chat_id = user_id
|
|
text = _extract_text(raw)
|
|
msgid = _first_non_empty(_pick(raw, "msgid", "msg_id", "id"), _pick(raw.get("message", {}), "msgid", "id"))
|
|
agentid = _first_non_empty(_pick(raw, "agentid", "agent_id"), _pick(raw.get("message", {}), "agentid"))
|
|
|
|
chat_type = _first_non_empty(_pick(raw, "chat_type", "conversation_type"))
|
|
is_group = bool(raw.get("is_group")) or chat_type in ("group", "room")
|
|
if not is_group and chat_id:
|
|
is_group = chat_id.endswith("@chatroom")
|
|
|
|
# If group but room id was missing, we previously fell back chat_id=user_id — same key as private 1:1.
|
|
if is_group and chat_id == user_id:
|
|
chat_id = f"group:unknown:{user_id}"
|
|
|
|
return {
|
|
"channel": "wecom",
|
|
"user_id": user_id,
|
|
"chat_id": chat_id or user_id,
|
|
"text": text,
|
|
"is_group": is_group,
|
|
"metadata": {
|
|
"agentid": agentid,
|
|
"msgid": msgid,
|
|
"source": "wecom_longconn",
|
|
"raw": raw,
|
|
},
|
|
}
|
|
|
|
|
|
def normalize_wecom_event_batch(obj: Any) -> list[dict[str, Any]]:
|
|
"""Extract event list from common envelopes returned by pull APIs."""
|
|
if isinstance(obj, list):
|
|
return [x for x in obj if isinstance(x, dict)]
|
|
if not isinstance(obj, dict):
|
|
return []
|
|
for key in ("events", "messages", "items", "data"):
|
|
arr = obj.get(key)
|
|
if isinstance(arr, list):
|
|
return [x for x in arr if isinstance(x, dict)]
|
|
return [obj]
|
|
|
|
|
|
__all__ = ["normalize_wecom_event", "normalize_wecom_event_batch"]
|