fix: 已出号后新一轮询价不带上一单字段
点名海运时丢掉旧陆运补问草稿,避免补字段误发填写样例图。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -25,7 +25,7 @@ from agent.channel.wecom.models import InboundMessage
|
||||
from agent.handlers.text_inquiry import handle_text_inquiry
|
||||
from agent.policy.air_text_flow import reset_air_text_flow_for_test
|
||||
from agent.policy.land_text_flow import get_land_text_flow, reset_land_text_flow_for_test
|
||||
from agent.policy.sea_text_flow import reset_sea_text_flow_for_test
|
||||
from agent.policy.sea_text_flow import get_sea_text_flow, reset_sea_text_flow_for_test
|
||||
from agent.routing.decision import RouteDecision
|
||||
from agent.routing.dispatch import dispatch_inbound
|
||||
from tests.test_sea_text_inquiry import COMPLETE_SEA
|
||||
@@ -323,6 +323,55 @@ class LandDispatchTests(unittest.TestCase):
|
||||
self.assertNotIn("你好,我是询价机器人", last)
|
||||
self.assertIn("请说明要调哪一项费用", last)
|
||||
|
||||
def test_sea_field_supplement_not_stolen_by_stale_land(self) -> None:
|
||||
"""
|
||||
旧陆运选项草稿不能抢走海运补问。
|
||||
|
||||
测服:先陆运缺选项,再发海运缺贸易条款/运输分类,下一句只补这两项,
|
||||
不能回陆运「参数提取不全」或填写样例图。
|
||||
"""
|
||||
store = get_message_store()
|
||||
handle_text_inquiry(
|
||||
InboundMessage(sender_id="mix-sea", message_id="m-land-old", content="陆运询价"),
|
||||
injected_facts={"起运港": "广州", "目的港": "深圳", "品名": "衣服"},
|
||||
injected_mode="LAND",
|
||||
store=store,
|
||||
)
|
||||
self.assertEqual(get_land_text_flow().session_of("mix-sea").phase, "need_land_options")
|
||||
incomplete = {
|
||||
"起运港": "上海",
|
||||
"目的港": "洛杉矶",
|
||||
"品名": "普货",
|
||||
"货量": "20吨",
|
||||
"整柜或拼柜": "整柜",
|
||||
"箱型箱量": "1x40HQ",
|
||||
}
|
||||
phase = handle_text_inquiry(
|
||||
InboundMessage(sender_id="mix-sea", message_id="m-sea-ask", content="海运询价"),
|
||||
injected_facts=incomplete,
|
||||
injected_mode="SEA",
|
||||
store=store,
|
||||
)
|
||||
self.assertEqual(phase, "clarify")
|
||||
self.assertEqual(get_sea_text_flow().session_of("mix-sea").phase, "clarify")
|
||||
self.assertIsNone(get_land_text_flow().session_of("mix-sea"))
|
||||
before = len(store._outbox)
|
||||
phase = handle_text_inquiry(
|
||||
InboundMessage(
|
||||
sender_id="mix-sea",
|
||||
message_id="m-sea-fill",
|
||||
content="贸易条款:FOB 运输分类:其他",
|
||||
),
|
||||
injected_facts={"贸易条款": "FOB", "运输分类": "其他"},
|
||||
store=store,
|
||||
)
|
||||
self.assertNotEqual(phase, "need_land_options")
|
||||
self.assertEqual(get_sea_text_flow().session_of("mix-sea").business_line, "SEA")
|
||||
added = "\n".join(i.content for i in list(store._outbox.values())[before:])
|
||||
self.assertNotIn("参数提取不全", added)
|
||||
self.assertNotIn("填写样例", added)
|
||||
self.assertNotIn("运输类型", added)
|
||||
|
||||
def test_clarify_short_reply_misrouted_as_other_stays_on_inquiry(self) -> None:
|
||||
"""补问阶段回「111」即使被标闲聊,也不能发开场白。"""
|
||||
store = get_message_store()
|
||||
|
||||
@@ -14,6 +14,7 @@ if ROOT not in sys.path:
|
||||
|
||||
from agent.schema.sea_options import (
|
||||
canonicalize_sea_class,
|
||||
drop_invented_door_trade_terms,
|
||||
harvest_sea_class,
|
||||
sea_class_prompt,
|
||||
)
|
||||
@@ -41,6 +42,13 @@ class SeaOptionsTest(unittest.TestCase):
|
||||
got = harvest_sea_class("运输分类:其他", {"运输分类": "Port to Port"})
|
||||
self.assertEqual(got["运输分类"], "其他")
|
||||
|
||||
def test_door_to_door_not_kept_as_trade_terms(self):
|
||||
text = "海运、纽约港到巴生西港,机器设备,40HQ*1,整柜,1.5KG,15CBM,15件"
|
||||
got = drop_invented_door_trade_terms(text, {"贸易条款": "门到门", "品名": "机器设备"})
|
||||
self.assertNotIn("贸易条款", got)
|
||||
kept = drop_invented_door_trade_terms("贸易条款:门到门", {"贸易条款": "门到门"})
|
||||
self.assertEqual(kept["贸易条款"], "门到门")
|
||||
|
||||
def test_prompt_lists_two_options_only(self):
|
||||
text = sea_class_prompt()
|
||||
self.assertIn("Port to Port", text)
|
||||
|
||||
@@ -28,6 +28,7 @@ from agent.handlers.group_collab import handle_group_collab
|
||||
from agent.handlers.text_inquiry import handle_text_inquiry
|
||||
from agent.ledger.memory_ledger import MemoryLedger
|
||||
from agent.policy import inquiry_copy as copy
|
||||
from agent.policy.air_text_flow import FlowSession
|
||||
from agent.policy.sea_text_flow import SeaTextInquiryFlow, reset_sea_text_flow_for_test
|
||||
from agent.schema.field_validate import SEA_COLLAB_FIELDS, validate_required_fields
|
||||
from agent.schema.tms_sea_query import assemble_sea_query
|
||||
@@ -273,6 +274,39 @@ class SeaTextInquiryTests(unittest.TestCase):
|
||||
self.assertIn("贸易条款", "\n".join(self.replies))
|
||||
self.assertFalse((self.flow.session_of("s-miss").work_order_no or "").startswith("WO"))
|
||||
|
||||
def test_leftover_door_to_door_not_written_as_trade_terms(self) -> None:
|
||||
"""旧草稿里的门到门不能写到确认卡贸易条款。测服 WO202609200013。"""
|
||||
leftover = {
|
||||
"起运港": "纽约港",
|
||||
"目的港": "巴生西港",
|
||||
"品名": "机器设备",
|
||||
"货量": "15件",
|
||||
"整柜或拼柜": "整柜",
|
||||
"箱型箱量": "40HQ*1",
|
||||
"贸易条款": "门到门",
|
||||
}
|
||||
self.flow._save(
|
||||
FlowSession(
|
||||
sender_id="s-door",
|
||||
thread_id="s-door",
|
||||
phase="clarify",
|
||||
business_line="SEA",
|
||||
facts=leftover,
|
||||
)
|
||||
)
|
||||
phase = self.flow.on_text(
|
||||
sender_id="s-door",
|
||||
text="海运、纽约港到巴生西港,机器设备,40HQ*1,整柜,1.5KG,15CBM,15件",
|
||||
reply=self._reply,
|
||||
injected_facts=dict(leftover),
|
||||
injected_mode="SEA",
|
||||
)
|
||||
self.assertEqual(phase, "clarify")
|
||||
joined = "\n".join(self.replies)
|
||||
self.assertNotIn("贸易条款:门到门", joined)
|
||||
self.assertIn("贸易条款", joined)
|
||||
self.assertNotEqual(self.flow.session_of("s-door").facts.get("贸易条款"), "门到门")
|
||||
|
||||
def test_harvest_class_from_reply_then_quotes(self) -> None:
|
||||
first = dict(COMPLETE_SEA)
|
||||
first.pop("运输分类")
|
||||
@@ -321,6 +355,44 @@ class SeaTextInquiryTests(unittest.TestCase):
|
||||
self.assertEqual(sess.business_line, "SEA")
|
||||
self.assertEqual(sess.status, "已报价")
|
||||
|
||||
def test_new_round_after_ticket_does_not_reuse_old_facts(self) -> None:
|
||||
"""上一单已出号,新一轮不能带上旧贸易条款。"""
|
||||
first = self.flow.on_text(
|
||||
sender_id="s-round",
|
||||
text="海运第一轮",
|
||||
reply=self._reply,
|
||||
injected_facts=COMPLETE_SEA,
|
||||
injected_mode="SEA",
|
||||
)
|
||||
self.assertEqual(first, "wait_collab")
|
||||
old_no = self.flow.session_of("s-round").work_order_no
|
||||
self.assertTrue((old_no or "").startswith("WO"))
|
||||
self.replies.clear()
|
||||
incomplete = {
|
||||
"起运港": "纽约港",
|
||||
"目的港": "巴生西港",
|
||||
"品名": "机器设备",
|
||||
"货量": "15件",
|
||||
"整柜或拼柜": "整柜",
|
||||
"箱型箱量": "40HQ*1",
|
||||
"运输分类": "Port to Port",
|
||||
}
|
||||
phase = self.flow.on_text(
|
||||
sender_id="s-round",
|
||||
text="海运、纽约港到巴生西港,机器设备,40HQ*1,整柜,1.5KG,15CBM,15件,Port to Port",
|
||||
reply=self._reply,
|
||||
injected_facts=incomplete,
|
||||
injected_mode="SEA",
|
||||
)
|
||||
self.assertEqual(phase, "clarify")
|
||||
joined = "\n".join(self.replies)
|
||||
self.assertNotIn("贸易条款:FOB", joined)
|
||||
self.assertNotIn("贸易条款:门到门", joined)
|
||||
self.assertIn("贸易条款", joined)
|
||||
sess = self.flow.session_of("s-round")
|
||||
self.assertNotEqual(sess.facts.get("贸易条款"), "FOB")
|
||||
self.assertNotEqual(sess.work_order_no, old_no)
|
||||
|
||||
def test_handler_routes_sea_not_air_deferred(self) -> None:
|
||||
reset_sea_text_flow_for_test()
|
||||
from agent.channel.queue import MemoryMessageStore
|
||||
|
||||
Reference in New Issue
Block a user