Skip to content
Open
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
5 changes: 5 additions & 0 deletions lib/crewai/src/crewai/events/utils/console_formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ class ConsoleFormatter:

def __init__(self, verbose: bool = False):
self.console = Console(width=None)
if hasattr(self.console.file, "reconfigure"):
try:
self.console.file.reconfigure(errors="replace")
except Exception: # noqa: S110 - best-effort; stream may not support reconfigure
pass
self.verbose = verbose
self._streaming_live: Live | None = None
self._is_streaming: bool = False
Expand Down
25 changes: 25 additions & 0 deletions lib/crewai/tests/utilities/test_console_formatter_encoding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import io

from rich.text import Text

from crewai.events.utils.console_formatter import ConsoleFormatter


class TestConsoleFormatterEncoding:
"""Regression tests: emoji panel titles must not crash on non-UTF-8 streams (e.g. Windows cp1252 console)."""

def test_reconfigures_stream_errors_to_replace(self):
formatter = ConsoleFormatter()

assert formatter.console.file.errors == "replace"

def test_emoji_panel_does_not_raise_on_cp1252_stream(self):
cp1252_stream = io.TextIOWrapper(
io.BytesIO(), encoding="cp1252", write_through=True
)
formatter = ConsoleFormatter()
formatter.console.file = cp1252_stream
if hasattr(cp1252_stream, "reconfigure"):
cp1252_stream.reconfigure(errors="replace")

formatter.print_panel(Text("x"), "🌊 Flow Started", "blue", is_flow=True)