From 20e40d75f99a12e06b44e6e7c65beeb1159b2b44 Mon Sep 17 00:00:00 2001 From: Yiorgis Gozadinos Date: Fri, 17 Apr 2026 16:31:23 +0300 Subject: [PATCH] add collapsible program display to chat TUI Co-Authored-By: Claude Opus 4.6 (1M context) --- .../haiku/rag/chat/widgets/chat_history.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/haiku_rag_slim/haiku/rag/chat/widgets/chat_history.py b/haiku_rag_slim/haiku/rag/chat/widgets/chat_history.py index fdd4f940..d619f76e 100644 --- a/haiku_rag_slim/haiku/rag/chat/widgets/chat_history.py +++ b/haiku_rag_slim/haiku/rag/chat/widgets/chat_history.py @@ -133,6 +133,25 @@ class CitationWidget(Collapsible): event.stop() +class ProgramWidget(Collapsible): + """Inline expandable program code block.""" + + def __init__(self, program: str, **kwargs) -> None: + content = f"```python\n{program}\n```" + super().__init__( + Markdown(content), + title="Program", + collapsed=True, + **kwargs, + ) + + def on_key(self, event: "Key") -> None: + """Handle Enter to toggle expand/collapse.""" + if event.key == "enter": + self.collapsed = not self.collapsed + event.stop() + + class ThinkingWidget(Static): """Thinking indicator shown while agent is processing.""" @@ -290,6 +309,22 @@ class ChatHistory(VerticalScroll): text-style: italic; } + /* Program */ + ProgramWidget { + margin: 0 0 0 2; + background: $surface; + } + + ProgramWidget > CollapsibleTitle { + padding: 0 1; + color: $text-muted; + } + + ProgramWidget Contents { + padding: 1 2; + background: $panel; + } + /* Thinking indicator */ ThinkingWidget { margin: 1 0 0 4; @@ -365,6 +400,13 @@ class ChatHistory(VerticalScroll): await self.mount(widget) self.scroll_end(animate=False) + async def add_program(self, program: str) -> None: + """Add a collapsible program block after a response.""" + if not program: + return + await self.mount(ProgramWidget(program)) + self.scroll_end(animate=False) + async def show_thinking(self, text: str = "Thinking...") -> None: """Show the thinking indicator.""" try: