Skip to content

Commit a958f31

Browse files
authored
Merge pull request #1856 from codeflash-ai/fix/structured-error-output-subagent-mode
fix: output structured XML errors in subagent mode
2 parents 33c8cc1 + bc7a5bf commit a958f31

2 files changed

Lines changed: 37 additions & 1 deletion

File tree

codeflash/code_utils/code_utils.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from codeflash.cli_cmds.console import logger, paneled_text
1919
from codeflash.code_utils.config_parser import find_pyproject_toml, get_all_closest_config_files
20-
from codeflash.lsp.helpers import is_LSP_enabled
20+
from codeflash.lsp.helpers import is_LSP_enabled, is_subagent_mode
2121

2222
_INVALID_CHARS_NT = {"<", ">", ":", '"', "|", "?", "*"}
2323

@@ -471,6 +471,11 @@ def exit_with_message(message: str, *, error_on_exit: bool = False) -> None:
471471
if is_LSP_enabled():
472472
logger.error(message)
473473
return
474+
if is_subagent_mode():
475+
from xml.sax.saxutils import escape
476+
477+
sys.stdout.write(f"<codeflash-error>{escape(message)}</codeflash-error>\n")
478+
sys.exit(1 if error_on_exit else 0)
474479
paneled_text(message, panel_args={"style": "red"})
475480

476481
sys.exit(1 if error_on_exit else 0)

tests/test_code_utils.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from codeflash.code_utils.code_utils import (
1010
cleanup_paths,
11+
exit_with_message,
1112
file_name_from_test_module_name,
1213
file_path_from_module_name,
1314
get_all_function_names,
@@ -751,3 +752,33 @@ def __init__(self):
751752
"""
752753
result = validate_python_code(code)
753754
assert result == code
755+
756+
757+
class TestExitWithMessageSubagent:
758+
@patch("codeflash.code_utils.code_utils.is_subagent_mode", return_value=True)
759+
def test_outputs_structured_xml_in_subagent_mode(self, _mock_subagent: MagicMock, capsys: pytest.CaptureFixture[str]) -> None:
760+
with pytest.raises(SystemExit) as exc_info:
761+
exit_with_message("Something went wrong", error_on_exit=True)
762+
assert exc_info.value.code == 1
763+
captured = capsys.readouterr()
764+
assert "<codeflash-error>" in captured.out
765+
assert "Something went wrong" in captured.out
766+
assert "</codeflash-error>" in captured.out
767+
768+
@patch("codeflash.code_utils.code_utils.is_subagent_mode", return_value=True)
769+
def test_escapes_xml_special_chars(self, _mock_subagent: MagicMock, capsys: pytest.CaptureFixture[str]) -> None:
770+
with pytest.raises(SystemExit):
771+
exit_with_message('File <foo> & "bar" not found', error_on_exit=True)
772+
captured = capsys.readouterr()
773+
assert "&lt;foo&gt;" in captured.out
774+
assert "&amp;" in captured.out
775+
776+
@patch("codeflash.code_utils.code_utils.is_subagent_mode", return_value=False)
777+
@patch("codeflash.code_utils.code_utils.is_LSP_enabled", return_value=False)
778+
def test_no_xml_when_not_subagent(
779+
self, _mock_lsp: MagicMock, _mock_subagent: MagicMock, capsys: pytest.CaptureFixture[str]
780+
) -> None:
781+
with pytest.raises(SystemExit):
782+
exit_with_message("Normal error", error_on_exit=True)
783+
captured = capsys.readouterr()
784+
assert "<codeflash-error>" not in captured.out

0 commit comments

Comments
 (0)