tui: async REST api client — stop blocking the event loop (Etap 3)
...
The terminal client's REST helpers were synchronous (httpx.Client); every
caller inside the Textual event loop (attach/switch/resume/profile/stop) blocked
the whole TUI for the duration of each network round-trip — the spinner froze,
input stopped responding, the screen did not repaint. Move the network layer to
async and a shared pooled client:
- api.py: all 7 helpers are now `async def` over a single lazily-created
httpx.AsyncClient (connection pooling) — awaits yield the loop while a request
is in flight, so the TUI never blocks on the network.
- tui_app.py + commands/builtin.py: every `api.*` call site is now `await`-ed
(all already ran in async workers / execute). _stop_stream_worker drops the
dead `iscoroutine` check (api.stop_session is async, the await is real).
- cli.py: _resolve_session_id and _handle_command await api.*; _run_raw wraps
the resolve + run in asyncio.run(_run_raw_async) so the sync click entrypoint
stays unchanged. Removed the now-unused _run_one_shot wrapper.
- sessions_picker.on_mount: list_sessions runs in a worker (run_worker) instead
of blocking on_mount — a slow/unreachable backend no longer hangs the modal;
the input is focusable immediately and the list populates when the request
returns.
Tests: every api mock across 6 client test files is now an `async def` fake
(test_tui_app, test_chat_panel, test_sessions_picker, test_terminal_client,
test_tui_export, test_input_box); the sessions picker tests use an async
_raise_not_found helper for the 404 path. Full suite: 939 passed, 1 skipped.
Eugene Sukhodolskiy
committed
11 hours ago