diff --git a/openhands-sdk/openhands/sdk/conversation/visualizer/default.py b/openhands-sdk/openhands/sdk/conversation/visualizer/default.py index d241baace..7bdb6ba2d 100644 --- a/openhands-sdk/openhands/sdk/conversation/visualizer/default.py +++ b/openhands-sdk/openhands/sdk/conversation/visualizer/default.py @@ -17,7 +17,7 @@ UserRejectObservation, ) from openhands.sdk.event.base import Event -from openhands.sdk.event.condenser import Condensation +from openhands.sdk.event.condenser import Condensation, CondensationRequest # These are external inputs @@ -252,6 +252,19 @@ def _create_event_panel(self, event: Event) -> Panel | None: border_style=_SYSTEM_COLOR, expand=True, ) + + elif isinstance(event, CondensationRequest): + title = f"[bold {_SYSTEM_COLOR}]" + if self._name: + title += f"{self._name} " + title += f"Condensation Request[/bold {_SYSTEM_COLOR}]" + return Panel( + content, + title=title, + border_style=_SYSTEM_COLOR, + padding=_PANEL_PADDING, + expand=True, + ) else: # Fallback panel for unknown event types title = f"[bold {_ERROR_COLOR}]" diff --git a/openhands-sdk/openhands/sdk/event/condenser.py b/openhands-sdk/openhands/sdk/event/condenser.py index eb4b98e05..6f58a45d1 100644 --- a/openhands-sdk/openhands/sdk/event/condenser.py +++ b/openhands-sdk/openhands/sdk/event/condenser.py @@ -55,6 +55,17 @@ class CondensationRequest(Event): source: SourceType = "environment" + @property + def visualize(self) -> Text: + text = Text() + text.append("Conversation Condensation Requested\n", style="bold") + message = ( + "A condensation of the conversation history has been requested to " + "manage context window usage.\n" + ) + text.append(message) + return text + class CondensationSummaryEvent(LLMConvertibleEvent): """This event represents a summary generated by a condenser.""" diff --git a/tests/sdk/conversation/test_visualizer.py b/tests/sdk/conversation/test_visualizer.py index 07355914f..d7c07b4fc 100644 --- a/tests/sdk/conversation/test_visualizer.py +++ b/tests/sdk/conversation/test_visualizer.py @@ -10,6 +10,7 @@ from openhands.sdk.event import ( ActionEvent, AgentErrorEvent, + CondensationRequest, MessageEvent, ObservationEvent, PauseEvent, @@ -290,6 +291,24 @@ def test_visualizer_user_reject_observation_panel(): assert "User rejected the proposed action." in renderable.plain +def test_visualizer_condensation_request_panel(): + """CondensationRequest should render a system-styled panel with friendly text.""" + visualizer = DefaultConversationVisualizer() + event = CondensationRequest() + panel = visualizer._create_event_panel(event) + assert panel is not None + # Should not fall back to UNKNOWN + assert "UNKNOWN Event" not in str(panel.title) + # Title should indicate condensation request (case-insensitive check on substring) + assert "Condensation Request" in str(panel.title) + # Body should be the friendly visualize text + renderable = panel.renderable + assert isinstance(renderable, Text) + body = renderable.plain + assert "Conversation Condensation Requested" in body + assert "condensation of the conversation history" in body + + def test_metrics_formatting(): """Test metrics subtitle formatting.""" from unittest.mock import MagicMock