fix(frontend): sync completed chat attempts#236
Conversation
warren618
left a comment
There was a problem hiding this comment.
Thanks @sambazhu — this is a useful, orthogonal addition. For context, two fixes for the same issue (#229) just merged: #234 (re-subscribe + replay SSE when returning to a running session) and #235 (responsive cancel). This PR targets a third, distinct gap — the UI staying in "streaming" after a run already committed because the SSE attempt.completed was missed (the long-standing replay race) — so it composes rather than overlaps. Verified the contract holds: sendMessage returns attempt_id (service emits attempt.created then runs in the background) and the assistant reply is stored with linked_attempt_id, so the poll key is correct.
A few things before merge:
-
Make it a true fallback (avoid firing on the happy path).
syncCompletedAttemptruns after every send and pollsgetSessionMessages3× even when SSE finalized the turn normally; on a sub-2.4s run it then re-forcesidle+ a secondgetSessionMessagesrefresh. Could you gate the reconcile on the UI still being mid-stream — e.g. onlyclearStreaming()/setStatus("idle")/refreshwhenact().status === "streaming"(and skip the poll loop entirely once it's alreadyidle)? That keeps it a no-op whenever SSE worked. -
Window scope. The 3×800ms (~2.4s) window only catches attempts that finish within it; a longer run whose completion event is genuinely missed stays stuck. Is the 2.4s the scenario you actually hit (a fast turn)? If so, a one-line note in the PR body is enough; if you meant to cover longer runs too, the reconnect/replay path from #234 is probably the better hook than a fixed poll budget.
-
Note
attempt.completedvs failed/cancelled. A failed or cancelled attempt also appends an assistant reply withlinked_attempt_id, so this will reconcile those too — which is fine (and desirable), just confirming it's intended. -
Please fill in the PR description (what scenario/repro this fixes) and add a frontend test (vitest) for the sync path — e.g. a completed attempt present in
getSessionMessageswhile the store is stillstreaming→ status flips toidleand history refreshes. That locks the behavior in.
Happy to merge once the fallback guard + a test are in. 🙏
|
Merged, thanks! This is the SSE-completion-drop sync (poll for the persisted assistant message after |
Summary
Why
Changes
Test Plan
pytest --ignore=agent/tests/e2e_backtest --tb=short -q)Checklist
src/agent/,src/session/,src/providers/) without prior discussion