"""Terminal rendering helpers for Navi WebSocket events."""
from __future__ import annotations
import click
class Renderer:
"""Render stream events to the terminal."""
def __init__(self, show_thinking: bool = False, show_events: bool = True) -> None:
self.show_thinking = show_thinking
self.show_events = show_events
self._thinking_buffer: list[str] = []
self._in_thinking = False
def _print(self, text: str = "", *, color: str | None = None, nl: bool = True) -> None:
click.secho(text, fg=color, nl=nl)
def render(self, msg: dict) -> None:
msg_type = msg.get("type")
if msg_type == "heartbeat":
return
if msg_type == "session_sync":
if self.show_events:
profile_id = msg.get("profile_id") or "unknown"
self._print(f"[session {msg.get('session_id')[:8]} | profile {profile_id}]", color="bright_black")
return
if msg_type == "stream_start":
if self.show_events:
self._print("[Navi] ", color="cyan", nl=False)
return
if msg_type == "thinking_delta":
if self.show_thinking:
self._thinking_buffer.append(msg.get("delta", ""))
return
if msg_type == "thinking_end":
if self.show_thinking and self._thinking_buffer:
self._print("\n[thinking]", color="bright_black")
self._print("".join(self._thinking_buffer), color="bright_black")
self._print("[/thinking]", color="bright_black")
self._thinking_buffer.clear()
return
if msg_type == "stream_delta":
self._print(msg.get("delta", ""), nl=False)
return
if msg_type == "tool_started":
if self.show_events:
tool = msg.get("tool", "?")
args = msg.get("args") or {}
self._print(f"\n[tool: {tool}]", color="yellow")
if args:
self._print(str(args), color="bright_black")
return
if msg_type == "tool_call":
if self.show_events:
tool = msg.get("tool", "?")
success = msg.get("success", True)
color = "green" if success else "red"
self._print(f"[tool result: {tool} success={success}]", color=color)
result = msg.get("result")
if result:
preview = str(result).replace("\n", " ")[:400]
self._print(preview, color="bright_black")
return
if msg_type == "stream_end":
self._print() # newline after response
return
if msg_type == "error":
self._print(f"\n[error] {msg.get('message', 'unknown error')}", color="red")
return
if msg_type == "context_compressed":
if self.show_events:
self._print("[context compressed]", color="bright_black")
return
if self.show_events:
self._print(f"[event: {msg_type}] {msg}", color="bright_black")