feat(ui): explicit chat state machine — typing indicator, streaming progress, timeout and error recovery

This commit is contained in:
2026-08-21 18:45:27 -04:00
parent 2364e1ee7d
commit e5810b0bcf
8 changed files with 642 additions and 40 deletions
+15
View File
@@ -4,6 +4,7 @@ from __future__ import annotations
import json
from app.api.chat import sse_event
from app.schemas import ChatErrorEvent
def _payload(frame: str) -> dict:
@@ -46,3 +47,17 @@ def test_multi_line_text_stays_one_frame() -> None:
frame = sse_event({"type": "delta", "text": "line1\nline2\n\n"})
assert frame.count("\n\n") == 1 # only the frame terminator
assert _payload(frame)["text"] == "line1\nline2\n\n"
def test_error_event_model_serializes_exact_frame() -> None:
"""The ``ChatErrorEvent`` model is the wire shape of every server-side
failure the UI's state machine (phase 06) must recover from."""
frame = sse_event(ChatErrorEvent(detail="boom").model_dump())
assert frame == 'data: {"type": "error", "detail": "boom"}\n\n'
assert _payload(frame) == {"type": "error", "detail": "boom"}
def test_error_event_shape_is_type_and_detail_only() -> None:
dumped = ChatErrorEvent(detail="The chat model dropped the connection").model_dump()
assert set(dumped.keys()) == {"type", "detail"}
assert dumped["type"] == "error" # default — call sites never spell it out