From cf1344858063d9135480d85537489a21feff78ce Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Sat, 19 Sep 2026 10:36:00 +0530 Subject: [PATCH] refactor(agent): name the tool-call XML namespace prefix once Gate fold: the optional-prefix regex was spelled three times in the agent stripper; it is one constant now (_NS_PREFIX). The cli.py docstring pointed at run_agent._strip_think_blocks, which moved to agent.agent_runtime_helpers.strip_think_blocks; stray blank lines dropped from the test file. --- agent/agent_runtime_helpers.py | 8 +++++--- cli.py | 2 +- tests/agent/test_strip_reasoning_tags_cli.py | 5 ----- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/agent/agent_runtime_helpers.py b/agent/agent_runtime_helpers.py index 18d65346fd..02f298bcde 100644 --- a/agent/agent_runtime_helpers.py +++ b/agent/agent_runtime_helpers.py @@ -35,11 +35,13 @@ logger = logging.getLogger(__name__) # Cap same-entry OAuth refreshes on a persistent auth failure, else a single-entry pool re-mints forever. _MAX_AUTH_REFRESH_ATTEMPTS = 2 _TOOL_CALL_TAG_NAMES = ("tool_call", "tool_calls", "tool_result", "function_call", "function_calls") +# Optional XML namespace prefix: some models serialize native tool calls as . +_NS_PREFIX = r"(?:[\w.-]+:)?" _REASONING_BLOCK_PATTERNS = tuple( re.compile(rf"<{name}>.*?", re.DOTALL | re.IGNORECASE) for name in THINK_TAG_NAMES ) _TOOL_CALL_BLOCK_PATTERNS = tuple( - re.compile(rf"<(?:[\w.-]+:)?{name}\b[^>]*>.*?", re.DOTALL | re.IGNORECASE) + re.compile(rf"<{_NS_PREFIX}{name}\b[^>]*>.*?", re.DOTALL | re.IGNORECASE) for name in _TOOL_CALL_TAG_NAMES ) @@ -56,7 +58,7 @@ _ORPHAN_REASONING_TAG_PATTERN = re.compile( rf'\s*', re.IGNORECASE ) _STRAY_TOOL_CALL_CLOSER_PATTERN = re.compile( - rf'\s*', re.IGNORECASE + rf'\s*', re.IGNORECASE ) # A tool-call opener with no closer, or GLM-style argument markup @@ -65,7 +67,7 @@ _STRAY_TOOL_CALL_CLOSER_PATTERN = re.compile( # can't be recovered; strip from the block-boundary opener (or the line # holding the first stray argument tag) to the end of the text. _UNTERMINATED_TOOL_CALL_PATTERN = re.compile( - rf'(?:^|\n)[ \t]*<(?:[\w.-]+:)?(?:{"|".join(_TOOL_CALL_TAG_NAMES)})\b[^>]*>.*$' + rf'(?:^|\n)[ \t]*<{_NS_PREFIX}(?:{"|".join(_TOOL_CALL_TAG_NAMES)})\b[^>]*>.*$' r'|(?:^|\n)[^\n<]* str: """Strip reasoning blocks (closed, unterminated, orphan-close) and leaked tool-call XML from display text. - Keep in sync with ``run_agent._strip_think_blocks`` and the stream consumer's think-tag sets. + Keep in sync with ``agent.agent_runtime_helpers.strip_think_blocks`` and the stream consumer's think-tag sets. Also strips tool-call XML blocks some open models leak into visible content (````, ````, Gemma-style ``…``). Ported from diff --git a/tests/agent/test_strip_reasoning_tags_cli.py b/tests/agent/test_strip_reasoning_tags_cli.py index df1c645cfc..cf8557544f 100644 --- a/tests/agent/test_strip_reasoning_tags_cli.py +++ b/tests/agent/test_strip_reasoning_tags_cli.py @@ -54,11 +54,6 @@ class TestToolCallStripping: assert out.strip() == "Waiting." - - - - - def test_empty_string(self): assert _strip_reasoning_tags("") == ""