fix(#422): escape Rich markup in all console content - #438
Open
LHMQ878 wants to merge 1 commit into
Open
Conversation
bytedance#341 wrapped error strings in `rich.text.Text` but then printed them via `console.print(f"\n{error_text}")`. Interpolating a `Text` into an f-string converts it back to `str`, so Rich re-parses it as markup and the escaping is undone — which is why the traceback in bytedance#422 still points at that line. Print the `Text` directly, and wrap `traceback.format_exc()` too, since a traceback carrying the same text crashes identically. The larger gap is that `rich.markup.escape` was never used anywhere. `generate_agent_step_table` interpolates model output, tool arguments, tool results, reflections and errors straight into table cells, and both `print_task_details` implementations interpolate the user's task description into markup. Any `[...]` shaped like a closing tag raises MarkupError there, which matches the report's note that the agent had been exploring parser/grammar code. Escape each of those values; the surrounding style tags stay markup so styling is unaffected. Covers both console types, since `generate_agent_step_table` is shared by the simple and rich consoles.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
trae-clicrashes withrich.errors.MarkupErrorwhenever text it displays happens to contain something Rich reads as a closing markup tag — e.g.[/'A', 1, /'B']in a tool result, or[/\-\+.$%*@?|]in model output. The crash masks the original error instead of reporting it.This is the remaining half of #281. #341 fixed part of it, but its own fix is undone by an f-string, and the main rendering path was never covered at all.
More Information
1.
Textinterpolated back into astr(the traceback in #422)#341 wrapped error strings in
rich.text.Text, which is markup-safe, but then printed three of them like this:Interpolating a
Textinto an f-string calls__str__and yields a plainstr, so Rich parses it as markup again and the escaping theTextexisted to provide is lost. That is exactly the line the reported traceback ends on (cli.py:408). The two sites in the same handler that print theTextdirectly never crashed — which is why the bug looked partially fixed.Fixed by emitting the newline separately and printing the
Textitself.traceback.format_exc()is now wrapped inTexttoo: it embeds the same exception message, soconsole.print(traceback.format_exc())on the very next line crashes identically — that print is on the path the issue expects to show "the original exception and traceback".2.
rich.markup.escapewas never used anywhere in the repogrep -rn escape trae_agent/returns no call sites. Meanwhilegenerate_agent_step_table(utils/cli/cli_console.py) interpolates raw, arbitrary text into table cells:LLM ResponseToolsReflectionErrorAny of these containing
[/...]raisesMarkupErrorwhen the table is rendered. This matches the reporter's note that "the agent explored parser/grammar code and tool output contained strings like the examples above" — grammar/parser source is full of bracketed tokens.print_task_detailsin bothsimple_console.pyandrich_console.pyhas the same problem withvalue, which includes the user's own task description, sotrae-cli run "fix the [/foo] parser"crashes before the agent even starts.Each of those values is now passed through
rich.markup.escape. The style tags the table emits itself ([{color}]…[/{color}],[cyan]…[/cyan],[bold]…[/bold]) stay unescaped, so styling is unchanged — one of the tests pins that.Because
generate_agent_step_tableis shared by the simple and rich consoles, one fix covers both--console-typevalues.Validation
New test file
tests/utils/test_cli_console_markup.py— 6 cases rendering anAgentStepthrough the realConsolewith the two markup-like strings from the bug report placed in LLM response / tool arguments / tool result / reflection / error, plus a case asserting the status row is still styled (i.e. the fix escapes content without escaping the table's own markup).Control experiment —
git stashthe source change and re-run: all 6 fail, withwhich is the same error class and message as the report.
No regressions: comparing the full
pytest tests/failure set before and after this change, the only difference is those 6 tests flipping from fail to pass. The 15 other failures are identical on both sides and pre-existing in my environment (Google / OpenRouter / Ollama tests need live API keys or a running Ollama; two bash / json_edit tests are Windows-specific).ruff checkandruff format --checkpass on all 5 files.mypyreports only the pre-existingdocker.errorsmissing-stubs error, confirmed identical with the change stashed.Verified against both
rich13.7.1 and 15.0.0.Linked Issues
Resolves #422
Related to #281