mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-24 16:54:43 +00:00
fix: escape triple-backtick in reasoning before wrapping in outer code block
B1: When reasoning content contains ``` e.g. model quoting code in its thinking, wrapping it in an outer ``` for display causes the inner fence to break the outer block. Adds escape_code_fences_for_display() in gateway/stream_consumer.py, called from gateway/run.py before wrapping reasoning in the outer ``` display block.
This commit is contained in:
parent
132e0005c8
commit
5e44413b7c
3 changed files with 67 additions and 0 deletions
|
|
@ -13671,6 +13671,7 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
if _show_reasoning_effective and response and not _intentional_silence:
|
||||
last_reasoning = agent_result.get("last_reasoning")
|
||||
if last_reasoning:
|
||||
from gateway.stream_consumer import escape_code_fences_for_display
|
||||
# Collapse long reasoning to keep messages readable
|
||||
lines = last_reasoning.strip().splitlines()
|
||||
if len(lines) > 15:
|
||||
|
|
@ -13702,6 +13703,9 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
)
|
||||
response = f"> 💭 **Reasoning:**\n{_quoted}\n\n{response}"
|
||||
else:
|
||||
# Escape ``` inside reasoning so inner fences don't
|
||||
# break the outer code block used to render it.
|
||||
display_reasoning = escape_code_fences_for_display(display_reasoning)
|
||||
response = f"💭 **Reasoning:**\n```\n{display_reasoning}\n```\n\n{response}"
|
||||
|
||||
# Runtime-metadata footer — only on the FINAL message of the turn.
|
||||
|
|
|
|||
|
|
@ -61,6 +61,24 @@ _COMMENTARY = object()
|
|||
_FLUSH = object()
|
||||
|
||||
|
||||
def escape_code_fences_for_display(text: str) -> str:
|
||||
"""Escape triple-backtick markers so text can be safely wrapped
|
||||
inside an outer ``` code block without breaking the fence.
|
||||
|
||||
When reasoning content contains ``` (e.g. the model quotes code
|
||||
in its thinking), wrapping it in an outer ``` for display causes
|
||||
the inner fence to break the outer block. Solution: replace each
|
||||
`` ``` `` with `` \\`\\`\\` `` before wrapping.
|
||||
|
||||
Returns:
|
||||
The input text with each `` ``` `` replaced by `` \\`\\`\\` ``,
|
||||
or the input unchanged if no triple-backticks are present.
|
||||
"""
|
||||
if not isinstance(text, str) or "```" not in text:
|
||||
return text
|
||||
return text.replace("```", "\\`\\`\\`")
|
||||
|
||||
|
||||
@dataclass
|
||||
class StreamConsumerConfig:
|
||||
"""Runtime config for a single stream consumer instance."""
|
||||
|
|
|
|||
45
tests/gateway/test_escape_reasoning_fences.py
Normal file
45
tests/gateway/test_escape_reasoning_fences.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
"""
|
||||
Tests for escape_code_fences_for_display.
|
||||
|
||||
B1: Escape triple-backtick markers inside reasoning text before wrapping
|
||||
in an outer ``` fence, so inner ``` doesn't break the outer block.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from gateway.stream_consumer import escape_code_fences_for_display
|
||||
|
||||
|
||||
class TestEscapeCodeFencesForDisplay:
|
||||
"""escape_code_fences_for_display prevents inner ``` from breaking
|
||||
the outer code block used to render reasoning."""
|
||||
|
||||
def test_no_fence_passthrough(self):
|
||||
text = "plain reasoning text"
|
||||
assert escape_code_fences_for_display(text) == text
|
||||
|
||||
def test_single_fence_escaped(self):
|
||||
text = "model used ```python\nx = 1\n``` in its thinking"
|
||||
result = escape_code_fences_for_display(text)
|
||||
assert "```" not in result
|
||||
assert "\\`\\`\\`" in result
|
||||
|
||||
def test_multiple_fences_all_escaped(self):
|
||||
text = "```\nblock1\n``` and ```python\nblock2\n```"
|
||||
result = escape_code_fences_for_display(text)
|
||||
assert result.count("```") == 0
|
||||
assert result.count("\\`\\`\\`") == 4
|
||||
|
||||
def test_empty_string(self):
|
||||
assert escape_code_fences_for_display("") == ""
|
||||
|
||||
def test_none_returns_none(self):
|
||||
assert escape_code_fences_for_display(None) is None
|
||||
|
||||
def test_integration_with_outer_fence(self):
|
||||
"""Simulates the gateway's reasoning wrapping logic."""
|
||||
raw = "thinking about:\n```python\nprint('hi')\n```\nok"
|
||||
escaped = escape_code_fences_for_display(raw)
|
||||
wrapped = f"💭 **Reasoning:**\n```\n{escaped}\n```\n\nHere's the answer."
|
||||
# The outer ``` should not be broken by inner ```
|
||||
assert wrapped.count("```") == 2 # only outer open + close
|
||||
assert "\\`\\`\\`" in wrapped
|
||||
Loading…
Add table
Add a link
Reference in a new issue