| 2026-07-12 |

Navi Code TUI: show context-compression summary in the chat
...
The server already sent the summary text in ContextCompressed.summary, but the
TUI never showed it — forced /compact printed a bare "N → M messages" line and
mid-turn auto-compress produced no chat feedback at all. Now both render a
distinct bordered block headed "Context compressed: N → M messages" with the
summary text (markdown) inside, so the user can see what the compressor kept.
- chat_model: new context_summary kind; context_compressed creates a chat item
carrying the summary + before/after counts (was explicitly ignored).
- renderers/summary: ContextSummaryRenderer — dim bordered panel, markdown body.
- chat_panel: _item_msg mapping for context_summary.
- tui_app: emit the summary item on context_compressed for both forced and
mid-turn cases; drop the now-redundant one-line status (the block header
carries the counts). Spinner start/stop/label logic unchanged.
- Tests: chat_model mapping + renderer (accepts/counts/text/missing-counts).
Summaries are live-only — not rebuilt on session reload (the compressor stores
them is_display=False, same as before for compression events).
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
11 hours ago
|
| 2026-07-11 |
tui: per-message chat widgets — render only the streaming bubble
...
ChatPanel used to hold a single Static rebuilt via update(Group(...)) on every
event, so a per-token stream_delta re-rendered all visible items (up to 200).
Now each message is its own _ChatItemView(Static); _sync() mounts new widgets at
the end, removes dropped ones, and signature-gated maybe_update re-renders only
the changed widget. On a stream only the streaming bubble repaints — the rest
stay mounted untouched. Public API stays synchronous (mount/remove are sync in
this Textual version), so tui_app is unchanged. Truncation hint is now a
dedicated top widget toggled via styles.display.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

Navi Code TUI: show request duration (live timer + chat metadata)
...
Live elapsed timer next to the activity indicator (ticks once per second
during a turn, format 2m 16s), driven by the same stream_start/stream_end
hooks as the activity indicator — so it spans the whole turn (all LLM calls,
tool calls, planning, sub-agent steps). On stream_end it syncs to the
backend's authoritative elapsed_seconds before freezing; on stream_stopped/
error/disconnect it freezes at the locally-measured value.
On stream_end the model also appends a turn_meta ChatItem rendered as a dim
"⏱ 2m 16s" line below the answer — the total time the agent spent on the
user's request. The value comes from stream_end.elapsed_seconds, already
measured by the backend over the whole turn, so the TUI needs no timer for
accuracy. stream_stopped/error do not get a metadata line (only completed
requests).
Shared format_duration(): None -> "—", <60s -> "16s", <3600 -> "2m 16s",
>=3600 -> "1h 2m".
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
tui: load session message history into the chat panel on resume
...
Resuming or switching a session showed a blank chat — the past conversation
was never replayed. GET /sessions/{id} already returns the messages; the TUI
just ignored them.
- ChatModel.load_history maps persisted Message dicts back to the same
ChatItems the live stream produces (user/assistant text, thinking, tool
started/result, plan), skipping is_display=False (context-only user,
summaries, compression events) so only what the user would have seen
live is rebuilt.
- ChatPanel.load_history wraps it (clears the render cache + refresh).
- attach_session loads the messages from get_session, so resume/switch
replays the history before the cwd/Connected banners.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
| 2026-07-10 |
tui: bound chat history render cost (cache + visible-item cap)
...
The chat panel rebuilt every renderable on each WS event, including
per-token stream_delta — so markdown was re-parsed for the entire history
on every token and the TUI lagged as conversations grew.
- Cache renderables keyed by id(item)+signature so only the changed item
(the streaming assistant bubble) is rebuilt per token; the rest are
reused. Prune orphaned entries so cache stays bounded by live items.
- Add max_visible_items TUI setting (default 200): render only the last
N items with a "… N earlier messages not shown" hint when truncated.
Items stay in the in-memory model (non-destructive) but are not laid
out, so per-refresh cost is constant regardless of history length.
- Rename the cache attr to _chat_render_cache to avoid collision with
Textual Widget._render_cache, which it resets on mount.
Co-Authored-By: Claude <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|