add collapsible program display to chat TUI
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7d98d0ec57
commit
20e40d75f9
1 changed files with 42 additions and 0 deletions
|
|
@ -133,6 +133,25 @@ class CitationWidget(Collapsible):
|
||||||
event.stop()
|
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):
|
class ThinkingWidget(Static):
|
||||||
"""Thinking indicator shown while agent is processing."""
|
"""Thinking indicator shown while agent is processing."""
|
||||||
|
|
||||||
|
|
@ -290,6 +309,22 @@ class ChatHistory(VerticalScroll):
|
||||||
text-style: italic;
|
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 */
|
/* Thinking indicator */
|
||||||
ThinkingWidget {
|
ThinkingWidget {
|
||||||
margin: 1 0 0 4;
|
margin: 1 0 0 4;
|
||||||
|
|
@ -365,6 +400,13 @@ class ChatHistory(VerticalScroll):
|
||||||
await self.mount(widget)
|
await self.mount(widget)
|
||||||
self.scroll_end(animate=False)
|
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:
|
async def show_thinking(self, text: str = "Thinking...") -> None:
|
||||||
"""Show the thinking indicator."""
|
"""Show the thinking indicator."""
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue