Make WhatsApp ops English-first for field deployments.

Default progress, quote wrappers, tool-error copy, and playbook recipes to English unless lang is explicitly zh.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-08-10 22:51:25 +08:00
parent 0ab5ab8c5a
commit 47fd83597e
11 changed files with 130 additions and 88 deletions

View file

@ -21,6 +21,14 @@ def test_channel_dispatch_defaults_to_expert_and_generalist() -> None:
assert lang == "auto"
def test_channel_dispatch_whatsapp_defaults_to_en() -> None:
store = _DummyStore()
interaction_mode, specialist, lang = _resolve_channel_dispatch(store, channel="whatsapp", account=None)
assert interaction_mode == "expert"
assert specialist == "generalist"
assert lang == "en"
def test_channel_dispatch_uses_global_settings() -> None:
store = _DummyStore(
{

View file

@ -412,10 +412,10 @@ def test_prepare_group_user_text_for_model_shared_chat_prefix() -> None:
def test_build_group_focus_instruction() -> None:
zh = build_group_focus_instruction()
en = build_group_focus_instruction(lang="en")
assert "群聊规则" in zh
en = build_group_focus_instruction()
zh = build_group_focus_instruction(lang="zh")
assert "current sender" in en
assert "群聊规则" in zh
def test_extract_group_quoted_message_and_build_context_block() -> None:
@ -431,8 +431,10 @@ def test_extract_group_quoted_message_and_build_context_block() -> None:
assert info["quoted_text"] == "服务器刚刚 502 了"
assert info["quoted_push_name"] == "Alice"
block = build_group_quoted_context_block(metadata=meta)
assert "[被引用消息]" in block
assert "[Quoted message]" in block
assert "Alice" in block
zh_block = build_group_quoted_context_block(metadata=meta, lang="zh")
assert "[被引用消息]" in zh_block
def test_should_inject_quoted_context_dedupes_recent_message() -> None:
@ -883,7 +885,7 @@ def test_inbound_group_injects_quoted_context_when_not_in_current_session(
}
)
assert out.get("ok") is True
assert "[被引用消息]" in captured["text"]
assert "[Quoted message]" in captured["text"]
assert "看起来像 OSPF 邻居抖动" in captured["text"]
_ = tenant_id, user_id
@ -965,6 +967,7 @@ def test_inbound_group_skips_quoted_context_when_already_in_current_session(
)
assert out.get("ok") is True
assert "[被引用消息]" not in captured["text"]
assert "[Quoted message]" not in captured["text"]
_ = tenant_id, user_id

View file

@ -41,9 +41,9 @@ class WhatsappProgressHelpersTests(unittest.TestCase):
self.assertTrue(should_forward_progress_text("oclaw: tools done (12000ms)"))
self.assertTrue(should_forward_progress_text("oclaw: image specialist (legacy multimodal HTTP)…"))
def test_humanize_progress_text(self) -> None:
self.assertIn("整理", humanize_progress_text(text="oclaw: tools done (9000ms)", lang="zh"))
self.assertIn("composing", humanize_progress_text(text="oclaw: tools done (9000ms)", lang="en").lower())
def test_humanize_defaults_to_english(self) -> None:
self.assertIn("CLI", str(humanize_long_tool(tool_name="mcp__netx__execManagedNe") or ""))
self.assertIn("composing", humanize_progress_text(text="oclaw: tools done (9000ms)").lower())
class WhatsappTurnProgressPublisherTests(unittest.TestCase):
@ -56,7 +56,7 @@ class WhatsappTurnProgressPublisherTests(unittest.TestCase):
pub = WhatsappTurnProgressPublisher(
enqueue=enqueue,
lang="zh",
lang="en",
is_group=False,
min_interval_sec=10.0,
enabled=True,
@ -67,7 +67,7 @@ class WhatsappTurnProgressPublisherTests(unittest.TestCase):
pub.on_tool_ui("tool_use_call", {"tool_name": "mcp__netx__execManagedNe"})
self.assertEqual(len(sent), 1)
self.assertIn("设备", sent[0][0])
self.assertIn("CLI", sent[0][0])
clock["t"] = 105.0
pub.on_tool_ui("tool_use_call", {"tool_name": "mcp__netx__queryUmeAlarms"})
@ -82,7 +82,7 @@ class WhatsappTurnProgressPublisherTests(unittest.TestCase):
clock["t"] = 122.0
pub.on_progress("oclaw: tools done (15000ms)")
self.assertEqual(len(sent), 3)
self.assertIn("整理", sent[2][0])
self.assertIn("composing", sent[2][0].lower())
def test_group_metadata_mentions_without_quote(self) -> None:
sent: list[tuple[str, dict[str, Any] | None]] = []
@ -101,7 +101,7 @@ class WhatsappTurnProgressPublisherTests(unittest.TestCase):
pub = WhatsappTurnProgressPublisher(
enqueue=lambda t, m: sent.append((t, m)),
lang="zh",
lang="en",
is_group=True,
inbound=_Inbound(),
min_interval_sec=1.0,
@ -109,6 +109,7 @@ class WhatsappTurnProgressPublisherTests(unittest.TestCase):
)
pub.on_tool_ui("tool_use_call", {"tool_name": "ume_alarm_xlsx_report"})
self.assertEqual(len(sent), 1)
self.assertIn("Excel", sent[0][0])
meta = sent[0][1] or {}
self.assertTrue(meta.get("mention_jids"))
self.assertNotIn("quote_stanza_id", meta)
@ -185,7 +186,7 @@ class WhatsappInboundProgressWiringTests(unittest.TestCase):
inbound_mod,
get_assistant_store=mock.MagicMock(return_value=self.store),
_build_admin_gateway_executor=mock.MagicMock(return_value=object()),
_resolve_channel_dispatch=mock.MagicMock(return_value=("expert", "ops", "zh")),
_resolve_channel_dispatch=mock.MagicMock(return_value=("expert", "ops", "en")),
), mock.patch("runtime.gateway.OclawGateway") as gw_cls, mock.patch(
"runtime.orchestration.group_ingest.should_process_group_inbound",
return_value=True,
@ -212,7 +213,7 @@ class WhatsappInboundProgressWiringTests(unittest.TestCase):
self.assertIn("inbound_reply", kinds)
progress_rows = [p for p, k in zip(pending, kinds) if k == "inbound_progress"]
self.assertTrue(progress_rows)
self.assertIn("设备", str(progress_rows[0].get("text") or ""))
self.assertIn("CLI", str(progress_rows[0].get("text") or ""))
progress_src = json.loads(str(progress_rows[0].get("source") or "{}"))
self.assertTrue(progress_src.get("mention_jids"))
self.assertFalse(progress_src.get("quote_stanza_id"))