落地空运群内协同与锁舱出站。

群里按 BOT 通道激活当前工单、航线报价和成交跟进;没有 TMS 报价编号时用工单字段补齐仍调锁舱,避免被本地规则拦住。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-16 17:25:42 +08:00
co-authored by Cursor
parent 12219cacb1
commit d9029dec89
62 changed files with 6772 additions and 159 deletions
+48 -6
View File
@@ -128,6 +128,18 @@ HANDLER_REGISTRY: dict[str, HandlerFn] = {
}
def _is_air_collab_room(message: InboundMessage) -> bool:
"""当前群已激活空运工单。查不到或海运群返回 False。"""
try:
from agent.handlers.air_group_collab import get_air_text_flow
from agent.policy.air_group_ops import bound_air_ticket
return bound_air_ticket(get_air_text_flow(), message.chat_id or "") is not None
except Exception:
logger.exception("判断空运协同群失败 chat=%s", getattr(message, "chat_id", ""))
return False
def resolve_handler(intent: str) -> Optional[HandlerFn]:
"""查表;未知意图返回 None。"""
return HANDLER_REGISTRY.get(intent)
@@ -144,14 +156,44 @@ def dispatch_inbound(message: InboundMessage, decision: RouteDecision) -> str:
from agent.policy import inquiry_copy as copy
event = str((message.raw or {}).get("event") or "").lower()
action = copy.canonical_button(message.content or "")
if event in {"template_card_event", "click", "templatecardevent"} or action in {
copy.BTN_DEAL,
copy.BTN_LOST,
copy.BTN_NEGOTIATE,
}:
raw_text = (message.content or "").strip()
# 只有真点卡才走成交卡;群里打「成交」两个字要当文字成交,不能当私聊点卡丢掉。
is_card_event = event in {"template_card_event", "click", "templatecardevent"}
is_card_key = raw_text.startswith(
(copy.BTN_DEAL_KEY + ":", copy.BTN_LOST_KEY + ":", copy.BTN_NEGOTIATE_KEY + ":")
)
if is_card_event or is_card_key:
_wrap_card(message)
return "card_action"
source = str((message.raw or {}).get("source") or "").lower()
if source in {"aibot", "aibot_bridge"}:
from agent.handlers.air_group_collab import handle_air_group
phase = handle_air_group(message)
logger.info("dispatch air_group phase=%s chat=%s", phase, message.chat_id)
return "air_group_collab"
# 发文件不能 @:空运群附件靠会话存档听见。
# 文字本应走 BOT;BOT 没推到时,存档里已经带 @询价小助手 的短句按空运补听。
kind = (message.msg_type or "text").lower()
air_room = _is_air_collab_room(message)
if source == "wshoto_archive" and kind in {"text", ""}:
from agent.routing.air_group_intent import is_missed_air_bot_at
if is_missed_air_bot_at(raw_text, room_already_air=air_room):
from agent.handlers.air_group_collab import handle_air_group
phase = handle_air_group(message)
logger.info("dispatch air_group archive_at phase=%s chat=%s", phase, message.chat_id)
return "air_group_collab"
if air_room:
if kind in {"file", "image", "video"}:
from agent.handlers.air_group_collab import handle_air_group
phase = handle_air_group(message)
logger.info("dispatch air_group archive_file phase=%s chat=%s", phase, message.chat_id)
return "air_group_collab"
logger.info("dispatch 空运群存档文字忽略,须 @ BOT chat=%s", message.chat_id)
return "air_archive_text_ignore"
phase = handle_group_collab(message)
logger.info("dispatch group_collab phase=%s chat=%s", phase, message.chat_id)
return "group_collab"