From 354ffab61688140b1d000ab01116fc1f07517a53 Mon Sep 17 00:00:00 2001 From: Petrus Pennanen Date: Sun, 27 Sep 2026 13:59:50 +0300 Subject: [PATCH] Strip reasoning whose opening tag never appeared (' answer') Co-Authored-By: Claude Opus 5.5 --- carwatch/grounding.py | 11 +++++++++++ tests/test_scaffold_leak.py | 17 +++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/carwatch/grounding.py b/carwatch/grounding.py index 4999169..b3e03dd 100644 --- a/carwatch/grounding.py +++ b/carwatch/grounding.py @@ -52,6 +52,12 @@ _THINK_BLOCK = re.compile(r"<(think|thinking|reasoning)>.*?", re.IGNORECASE | re.DOTALL) +# A reasoning block whose OPENING tag was never in the output: chat templates +# that start the model inside (Qwen3.6 on the VTA, 27 Sep 2026) make +# it emit "...reasoning... answer", or just " answer" when the +# reasoning went to a separate field. The paired pattern above cannot see it, +# and the bare tag was posted to the room and handed to the voice. +_THINK_CLOSE = re.compile(r"", re.IGNORECASE) _BULLET = re.compile(r"^\s*(?:[-*\u2022]|\d+[.)])\s+") @@ -68,6 +74,11 @@ def strip_scaffold(text: str) -> str: if not text: return text cleaned = _THINK_BLOCK.sub("", text).strip() + closes = list(_THINK_CLOSE.finditer(cleaned)) + if closes: + after = cleaned[closes[-1].end():].strip() + if after: + cleaned = after lines = cleaned.splitlines() i, dropping = 0, False while i < len(lines): diff --git a/tests/test_scaffold_leak.py b/tests/test_scaffold_leak.py index 5a0f1b6..7d978fd 100644 --- a/tests/test_scaffold_leak.py +++ b/tests/test_scaffold_leak.py @@ -58,5 +58,22 @@ def test_prompt_and_stripper_share_the_headings(self): self.assertIn(CANNOT_HEADING, p) + +class StrayThinkClose(unittest.TestCase): + """VTA 27 Sep: ' Kuule, Petrus, ...' reached the room and the voice.""" + + def test_bare_closing_tag_is_dropped(self): + self.assertEqual(strip_scaffold(" Kuule, Petrus."), "Kuule, Petrus.") + + def test_reasoning_before_unopened_close_is_dropped(self): + self.assertEqual(strip_scaffold("The user greets me.\nI should reply.\nHello Petrus!"), + "Hello Petrus!") + + def test_paired_block_still_works(self): + self.assertEqual(strip_scaffold("hmmHi."), "Hi.") + + def test_only_reasoning_is_not_emptied(self): + self.assertTrue(strip_scaffold("thinking only").strip()) + if __name__ == "__main__": unittest.main()