From ad507cd54a02478c8df09bb000e5fe5912629b10 Mon Sep 17 00:00:00 2001 From: dullfig Date: Sun, 11 Jan 2026 14:30:36 -0800 Subject: [PATCH] Fix TUI console response display - Add thread-safe invalidation for cross-task updates - Fix response handler to properly route to TUI output - Add debug output if console hook fails Co-Authored-By: Claude Opus 4.5 --- agentserver/console/tui_console.py | 17 ++++++++++++++--- handlers/hello.py | 14 ++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/agentserver/console/tui_console.py b/agentserver/console/tui_console.py index c5ad4bd..847fbe4 100644 --- a/agentserver/console/tui_console.py +++ b/agentserver/console/tui_console.py @@ -253,8 +253,7 @@ class TUIConsole: self._print_simple(text, style) else: self.output.append(text, style) - if self.app and self.app.is_running: - self.app.invalidate() + self._invalidate() def print_raw(self, text: str, style: str = "output"): """Print without timestamp.""" @@ -262,7 +261,19 @@ class TUIConsole: self._print_simple(text, style) else: self.output.append_raw(text, style) - if self.app and self.app.is_running: + self._invalidate() + + def _invalidate(self): + """Invalidate the app to trigger redraw (thread-safe).""" + if self.app and self.app.is_running: + # Use call_soon_threadsafe for cross-task updates + try: + loop = self.app.loop + if loop and loop.is_running(): + loop.call_soon_threadsafe(self.app.invalidate) + else: + self.app.invalidate() + except Exception: self.app.invalidate() def _print_simple(self, text: str, style: str = "output"): diff --git a/handlers/hello.py b/handlers/hello.py index 0fb086e..e1ab1e6 100644 --- a/handlers/hello.py +++ b/handlers/hello.py @@ -126,15 +126,21 @@ async def handle_response_print(payload: ShoutedResponse, metadata: HandlerMetad Routes output to the TUI console if available, otherwise prints to stdout. """ + console = None try: from run_organism import get_console console = get_console() - if console and hasattr(console, 'on_response'): - console.on_response("response", payload) - return None except ImportError: pass - # Fallback: print to stdout + if console and hasattr(console, 'on_response'): + try: + console.on_response("shouter", payload) + return # Success - don't fall through to print + except Exception as e: + # Debug: show error but continue to fallback + print(f"\n\033[31m[console error] {e}\033[0m") + + # Fallback: print to stdout (only if console not available or failed) print(f"\n\033[36m[response] {payload.message}\033[0m") return None