tui: throttle streaming markdown rebuild + cache height (Etap 2)
The assistant bubble re-parsed rich Markdown on every stream_delta and rich-rendered it
twice per delta (once to paint, once to measure height) — O(N^2) over the answer length.
Fix the cost while keeping live markdown formatting:

- _ChatItemView.maybe_update now throttles assistant_message rebuilds to ~one per 150 ms
  (coalesced via set_timer). The ChatItem content still updates per delta; only the
  Markdown parse + rich render is deferred. Plain renderables (thinking/planning are
  Text) bypass the throttle — they are cheap. The first mutating delta rebuilds
  immediately for a snappy start; rapid bursts coalesce.
- get_content_height is cached by (renderable identity, width) so the layout pass no
  longer re-renders the rich renderable to measure it between throttled rebuilds.
- stream_end flushes any pending throttled rebuild so the final chunk of streamed text
  appears immediately instead of after the throttle window.
- A deferred rebuild re-anchors scroll to the bottom (via ChatPanel._stick_to_bottom)
  so the freshly rendered streaming text stays in view after its height grows.
- ThemedMarkdownRenderable.__rich_console__ now streams segments straight through
  instead of materializing them into a list first (no per-paint O(N) allocation +
  double walk); the link rewrite is inline in the loop.

Tests: adapted test_per_token_refresh_renders_only_the_streaming_item to the throttled
semantics (a burst yields a couple of rebuilds, not one per token, all for the assistant
item); added throttle-coalesces and stream_end-flushes tests. Full suite: 939 passed, 1 skipped.
1 parent 3bae766 commit 658196309c59275a9c23099691a761c4d1276eb9
@Eugene Sukhodolskiy Eugene Sukhodolskiy authored 6 hours ago
Showing 3 changed files
View
clients/terminal/tui/renderers/markdown_content.py
View
clients/terminal/tui/widgets/chat_panel.py
View
tests/clients/test_chat_panel.py