Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,37 @@ def _strip_code_fences(content: str) -> str:

Many LLM providers (MiniMax, some Ollama models, Claude via proxies)
wrap JSON responses in ```json ... ``` fences even when json_object
response format is requested. This strips the fences while preserving
the JSON content inside. Returns the original content unchanged if
no fences are detected.
response format is requested. This strips the fences only when the
candidate parses as JSON. Returns the original content unchanged if
no parseable JSON wrapper is detected.
"""
if "```" not in content:
return content
try:
if "```json" in content:
return content.split("```json")[1].split("```")[0].strip()
return content.split("```")[1].split("```")[0].strip()
except (IndexError, ValueError):
return content

fence_match = re.search(r"```(?:json)?\s*\n?(?P<body>.*?)\n?```", content, flags=re.DOTALL)
if fence_match:
fenced_body = fence_match.group("body").strip()
if fenced_body.startswith(("{", "[")):
try:
json.loads(fenced_body)
return fenced_body
except json.JSONDecodeError:
pass

starts = [index for index in (content.find("{"), content.find("[")) if index >= 0]
ends = [index for index in (content.rfind("}"), content.rfind("]")) if index >= 0]
if starts and ends:
start = min(starts)
end = max(ends)
if end > start:
candidate = content[start : end + 1].strip()
try:
json.loads(candidate)
return candidate
except json.JSONDecodeError:
pass

return content


# Reasoning/thinking tags emitted by extended-thinking models. Some providers
Expand Down
40 changes: 34 additions & 6 deletions hindsight-api-slim/tests/test_strip_code_fences.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Tests for _strip_code_fences helper in OpenAI-compatible LLM provider."""

import json

import pytest

from hindsight_api.engine.providers.openai_compatible_llm import _strip_code_fences
Expand Down Expand Up @@ -32,9 +34,8 @@ def test_fence_with_trailing_whitespace(self):
def test_fence_with_leading_whitespace(self):
"""Content with leading whitespace before fence."""
content = ' ```json\n{"facts": []}\n```'
# The function checks for ``` in content, not startswith
result = _strip_code_fences(content)
assert '{"facts": []}' in result
assert result == '{"facts": []}'

def test_no_fences_no_change(self):
"""Content without any backticks passes through."""
Expand All @@ -57,8 +58,37 @@ def test_malformed_fence_returns_original(self):
"""Malformed fences (missing closing) return something parseable."""
content = '```json\n{"facts": []}'
result = _strip_code_fences(content)
# Should attempt to strip and return best effort
assert isinstance(result, str)
assert result == '{"facts": []}'

@pytest.mark.parametrize(
"content",
[
"```\nthis is not json\n```",
"```json\n```",
],
)
def test_non_json_fence_returns_original(self, content):
"""Non-JSON fenced content is not converted into a bad JSON candidate."""
assert _strip_code_fences(content) == content

def test_json_with_nested_backticks_in_string(self):
"""Backticks inside a JSON string do not truncate the extracted JSON."""
content = '```json\n{"facts": [{"what": "saw ```nested``` marker"}]}\n```'

result = _strip_code_fences(content)

assert json.loads(result) == {"facts": [{"what": "saw ```nested``` marker"}]}

@pytest.mark.parametrize(
"content",
[
'Reasoning first.\n```json\n{"facts": []}\n```\nDone.',
'Reasoning first.\n```json\n{"facts": []}\nDone.',
],
)
def test_extracts_parseable_json_from_surrounding_text(self, content):
"""Provider prose around a JSON payload does not force a retry."""
assert _strip_code_fences(content) == '{"facts": []}'

def test_minimax_style_response(self):
"""Real-world MiniMax response format."""
Expand All @@ -85,8 +115,6 @@ def test_minimax_style_response(self):
assert not result.startswith("```")
assert not result.endswith("```")
# Should be valid JSON
import json

parsed = json.loads(result)
assert len(parsed["facts"]) == 1
assert parsed["facts"][0]["who"] == "Sebastian"