fix(chat,channels): admin session delete, weixin inbound, PG and docs

- List/delete chat sessions for administrator by username (cross-tenant UUID)

- Return 404 when delete does not remove a session; add tests

- Weixin: dispatch lang, inbound attachments, reply persist, native reply timeout

- PG compat scrub and administrator session delete repo path

- RUNBOOK: WhatsApp re-bind with Remove-Item auth; weixin poll diag scripts

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-06-03 01:36:45 +08:00
parent 39fd1905b6
commit bc1b45a8fd
20 changed files with 1056 additions and 86 deletions

View file

@ -49,6 +49,40 @@ def _now_ms() -> int:
return int(time.time() * 1000)
def _native_reply_timeout_sec() -> float:
raw = str(os.getenv("AIA_CHANNEL_NATIVE_REPLY_TIMEOUT_SEC") or "90").strip()
try:
value = float(raw)
except ValueError:
value = 90.0
return max(10.0, min(value, 600.0))
async def _run_native_reply_usecase(payload: dict[str, Any]) -> dict[str, Any]:
timeout = _native_reply_timeout_sec()
try:
return await asyncio.wait_for(
asyncio.to_thread(_process_inbound_payload_usecase, payload),
timeout=timeout,
)
except asyncio.TimeoutError:
channel = _normalize_channel(payload.get("channel"))
chat_id = str(payload.get("chat_id") or payload.get("user_id") or "").strip()
return {
"ok": False,
"error": "native_reply_timeout",
"replies": [
{
"channel": channel,
"chat_id": chat_id,
"text": "处理超时,请稍后再试。",
"attachments": [],
"metadata": {},
}
],
}
def _normalize_channel(raw: Any) -> str:
ch = str(raw or "wechat").strip().lower()
return ch if ch else "wechat"
@ -468,7 +502,7 @@ async def weixin_native_reply(
return {"ok": False, "error": "missing user_id", "replies": []}
if not str(payload.get("account_id") or "").strip():
return {"ok": False, "error": "missing account_id", "replies": []}
out = await asyncio.to_thread(_process_inbound_payload_usecase, payload)
out = await _run_native_reply_usecase(payload)
replies = out.get("replies") if isinstance(out, dict) else []
if not isinstance(replies, list):
replies = []
@ -490,7 +524,7 @@ async def whatsapp_native_reply(
return {"ok": False, "error": "missing user_id", "replies": []}
if not str(payload.get("account_id") or "").strip():
return {"ok": False, "error": "missing account_id", "replies": []}
out = await asyncio.to_thread(_process_inbound_payload_usecase, payload)
out = await _run_native_reply_usecase(payload)
replies = out.get("replies") if isinstance(out, dict) else []
if not isinstance(replies, list):
replies = []