feat(ui): explicit chat state machine — typing indicator, streaming progress, timeout and error recovery
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user