fix(converter): fall through when JSON regex match isn't valid JSON

This commit is contained in:
Greyson LaLonde
2026-05-01 00:48:09 +08:00
committed by GitHub
parent 864f0a8a91
commit 70f391994e
2 changed files with 40 additions and 3 deletions

View File

@@ -257,12 +257,21 @@ def handle_partial_json(
match = _JSON_PATTERN.search(result)
if match:
try:
exported_result = model.model_validate_json(match.group())
parsed = json.loads(match.group(), strict=False)
except json.JSONDecodeError:
return convert_with_instructions(
result=result,
model=model,
is_json_output=is_json_output,
agent=agent,
converter_cls=converter_cls,
)
try:
exported_result = model.model_validate(parsed)
if is_json_output:
return exported_result.model_dump()
return exported_result
except json.JSONDecodeError:
pass
except ValidationError:
raise
except Exception as e:

View File

@@ -177,6 +177,34 @@ def test_handle_partial_json_with_invalid_partial(mock_agent: Mock) -> None:
assert output == "Converted result"
def test_handle_partial_json_accepts_literal_control_chars_in_strings() -> None:
"""JSON values with literal newlines/tabs (lenient parsing) must still
validate, matching the prior model_validate_json behavior.
"""
result = 'prefix {"name": "Charlie\nDoe", "age": 35} suffix'
output = handle_partial_json(result, SimpleModel, False, None)
assert isinstance(output, SimpleModel)
assert output.name == "Charlie\nDoe"
assert output.age == 35
def test_handle_partial_json_falls_through_for_non_json_curly_blocks(
mock_agent: Mock,
) -> None:
"""A regex match that is not actually JSON (e.g. GraphQL) must fall through
to convert_with_instructions instead of raising a ValidationError.
"""
result = (
"type Query {\n countries: [Country]\n}\n\n"
"type Country {\n code: String\n name: String\n}"
)
with patch("crewai.utilities.converter.convert_with_instructions") as mock_convert:
mock_convert.return_value = "Converted result"
output = handle_partial_json(result, SimpleModel, False, mock_agent)
assert output == "Converted result"
mock_convert.assert_called_once()
# Tests for convert_with_instructions
@patch("crewai.utilities.converter.create_converter")
@patch("crewai.utilities.converter.get_conversion_instructions")