diff --git a/nanobot/channels/msteams.py b/nanobot/channels/msteams.py index b3c886bda..b3fa094b9 100644 --- a/nanobot/channels/msteams.py +++ b/nanobot/channels/msteams.py @@ -300,7 +300,7 @@ class MSTeamsChannel(BaseChannel): while preview_lines and not preview_lines[0]: preview_lines.pop(0) first_line = preview_lines[0] if preview_lines else "" - looks_like_quote_wrapper = first_line.lower().startswith("replying to ") or first_line.startswith("FWDIOC-BOT") + looks_like_quote_wrapper = first_line.lower().startswith("replying to ") or first_line.startswith("Quoted reply") if reply_to_id or channel_data.get("messageType") == "reply" or looks_like_quote_wrapper: text = self._normalize_teams_reply_quote(text) @@ -333,10 +333,10 @@ class MSTeamsChannel(BaseChannel): reply = "\n".join(lines[1:]).strip() return self._format_reply_with_quote(quoted, reply) - # Observed FWDIOC relay wrapper where the quoted content is surfaced after a - # synthetic "FWDIOC-BOT" header, sometimes with a blank line separating quote + # Observed quoted-reply wrapper where the quoted content is surfaced after a + # synthetic "Quoted reply" header, sometimes with a blank line separating quote # and reply, and sometimes as a compact line-based fallback shape. - if lines and lines[0].strip().startswith("FWDIOC-BOT"): + if lines and lines[0].strip().startswith("Quoted reply"): body = normalized_newlines.split("\n", 1)[1] if "\n" in normalized_newlines else "" body = body.lstrip() parts = re.split(r"\n\s*\n", body, maxsplit=1) @@ -354,10 +354,10 @@ class MSTeamsChannel(BaseChannel): return self._format_reply_with_quote(quoted, reply) # Observed compact fallback where the relay flattens quote and reply into - # a single line after the synthetic FWDIOC-BOT prefix. + # a single line after the synthetic Quoted reply prefix. compact = re.sub(r"\s+", " ", normalized_newlines).strip() - if compact.startswith("FWDIOC-BOT "): - compact = compact[len("FWDIOC-BOT ") :].strip() + if compact.startswith("Quoted reply "): + compact = compact[len("Quoted reply ") :].strip() for boundary in (". ", "! ", "? ", "… "): idx = compact.rfind(boundary) if idx == -1: diff --git a/tests/test_msteams.py b/tests/test_msteams.py index 7d07913be..bb4e7a4fe 100644 --- a/tests/test_msteams.py +++ b/tests/test_msteams.py @@ -223,11 +223,11 @@ def test_sanitize_inbound_text_keeps_normal_inline_message(make_channel): assert ch._sanitize_inbound_text(activity) == "normal inline message" -def test_sanitize_inbound_text_normalizes_fwdioc_wrapper_without_reply_metadata(make_channel): +def test_sanitize_inbound_text_normalizes_quoted_reply_wrapper_without_reply_metadata(make_channel): ch = make_channel() activity = { - "text": "FWDIOC-BOT \r\nQuoted prior message\r\n\r\nThis is a reply with quote test", + "text": "Quoted reply \r\nQuoted prior message\r\n\r\nThis is a reply with quote test", "channelData": {}, } @@ -249,11 +249,11 @@ def test_sanitize_inbound_text_structures_reply_quote_prefix(make_channel): assert ch._sanitize_inbound_text(activity) == "User is replying to: Bob Smith\nUser reply: actual reply text" -def test_sanitize_inbound_text_structures_live_fwdioc_quote_shape(make_channel): +def test_sanitize_inbound_text_structures_live_quoted_reply_shape(make_channel): ch = make_channel() activity = { - "text": "FWDIOC-BOT Got it. I’ll watch for the exact text reply with quote test and then inspect that turn specifically. Reply with quote test", + "text": "Quoted reply Got it. I’ll watch for the exact text reply with quote test and then inspect that turn specifically. Reply with quote test", "replyToId": "parent-activity", "channelData": {"messageType": "reply"}, } @@ -272,12 +272,12 @@ def test_normalize_teams_reply_quote_leaves_plain_text_test_phrase_untouched(mak assert ch._normalize_teams_reply_quote(text) == text -def test_sanitize_inbound_text_structures_multiline_fwdioc_quote_shape(make_channel): +def test_sanitize_inbound_text_structures_multiline_quoted_reply_shape(make_channel): ch = make_channel() activity = { "text": ( - "FWDIOC-BOT\r\n" + "Quoted reply\r\n" "Understood — then the restart already happened, and the new Teams quote normalization should now be live. " "Next best step: • send one more real reply-with-quote message in Teams • I&rsquo…\r\n" "\r\n" @@ -294,12 +294,12 @@ def test_sanitize_inbound_text_structures_multiline_fwdioc_quote_shape(make_chan ) -def test_sanitize_inbound_text_structures_exact_live_crlf_fwdioc_shape(make_channel): +def test_sanitize_inbound_text_structures_exact_live_crlf_quoted_reply_shape(make_channel): ch = make_channel() activity = { "text": ( - "FWDIOC-BOT \r\n" + "Quoted reply \r\n" "Please send one real reply-with-quote message in Teams. That single test should be enough now: " "• I’ll check the new MSTeams sanitized inbound text ... log • and compare it to the prompt…\r\n" "\r\n"