Documentation Index
Fetch the complete documentation index at: https://simplellmfunc.cn/llms.txt
Use this file to discover all available pages before exploring further.
TUI
The @tui decorator wraps a @llm_chat agent into a full Textual terminal UI with streaming output, tool visualization, and input handling.
Basic Usage
from SimpleLLMFunc import llm_chat, OpenAICompatible
from SimpleLLMFunc.utils.tui import tui
models = OpenAICompatible.load_from_json_file("provider.json")
llm = models["openrouter"]["openai/gpt-4o"]
@tui
@llm_chat(llm_interface=llm, toolkit=[...], stream=True)
async def agent(message: str, history: list | None = None, _abort_signal=None):
"""A helpful assistant."""
pass
if __name__ == "__main__":
agent()
Run it and you get a full chat interface in the terminal.
Features
- Streaming display — Model responses appear character-by-character
- Tool call cards — Each tool call gets a visual card showing name, arguments, and result
- Specialized cards —
execute_code, read_file, grep, sed, echo_into have custom rendering
- Abort —
Ctrl+C cancels the current response
- Copy —
Ctrl+Y copies the full transcript to clipboard
- Multi-column forks — When using SelfRef forks, child agents get their own columns
Slash Commands
| Command | Action |
|---|
/exit, /quit, /q | Quit the TUI |
/copy, /copyall | Copy transcript to clipboard |
/chat <msg> | Send a message (bypasses tool-input mode) |
Custom Event Hooks
Handle custom events (e.g., PyRepl streaming output) with hooks:
from SimpleLLMFunc.hooks.events import CustomEvent
from SimpleLLMFunc.utils.tui import ToolRenderSnapshot
def my_event_hook(event: CustomEvent, snapshot: ToolRenderSnapshot):
"""Process custom events for display."""
if event.event_name == "kernel_stdout":
# Handle PyRepl stdout streaming
pass
return None
@tui(custom_event_hook=[my_event_hook])
@llm_chat(llm_interface=llm, toolkit=repl.toolset, stream=True)
async def agent(message: str, history: list | None = None, _abort_signal=None):
"""My agent."""
pass
Decorator Parameters
| Parameter | Type | Description |
|---|
custom_event_hook | List[Callable] | Custom event handler functions |
title | str | Window title |
Passed to event hooks with context about the current tool card:
@dataclass
class ToolRenderSnapshot:
tool_name: str
tool_call_id: str
status: str # "running", "completed", "error"
arguments: dict
Keyboard Shortcuts
| Key | Action |
|---|
Ctrl+C | Abort current response |
Ctrl+Q | Quit |
Ctrl+Y | Copy transcript |
Enter | Send message |
When to Use @tui vs Custom UI
Use @tui when:
- You want a working chat interface quickly
- The built-in tool cards are sufficient
- You don’t need custom widgets or layouts
Build custom when:
- You need confirmation modals for dangerous actions
- You want a status bar with custom metrics
- You need non-chat UI elements (file trees, progress bars)
- You’re building a product, not a tool
For custom UIs, consume the ReactOutput stream directly and render with Textual or any other framework.