fix(socket): avoid replaying resumed thread on reconnect
Summary
Avoid replaying a persisted thread when a live WebSocket session reconnects, while still completing an initial restore that was pending when the first socket disconnected.
Serialize resume processing per session. Cache the completed server restore so a failed client notification can be retried without rerunning on_chat_resume or adding historical messages again. Clear the pending marker after successful delivery or a terminal not-found result. Existing on_chat_start behavior is preserved.
Regression coverage includes reconnecting before the first confirmation event, propagated callback failures, notification failure, concurrent reconnects, and avoiding repeated terminal errors.
Fixes #3061
Verification
pytest backend/tests/test_socket.py backend/tests/test_session.py backend/tests/test_context.py backend/tests/test_emitter.py -q -p no:cacheprovider: 107 passed (one existing Pydantic deprecation warning).- Ruff lint and format checks on the four changed files: passed.
git diff --check: passed.- Full
pytest -qcollection is blocked by eight import errors for optional storage and integration dependencies (google.auth,boto3,asyncpg,sqlalchemy,langchain_core, andllama_index).
Prepared with Codex assistance.
Review follow-up
Keep completed server initialization pending when Socket.IO observes a disconnect before or during resume notification, or when the target SID changes while the emit is suspended. A connected retry receives the cached thread and interaction metadata without rerunning the resume callback or adding historical messages again.
Regression tests reproduce the silent no-op delivery (not just a raised exception), SID replacement during delivery, and an interaction marker lost across reconnection while the callback is running. Related socket/session/context/emitter tests: 107 passed on Python 3.13, with one existing Pydantic deprecation warning. Ruff lint and format checks and diff whitespace checks passed. Socket.IO connection state detects server-observed disconnects; this does not introduce a browser acknowledgement protocol.
Summary by cubic
Fixes socket reconnects so a live session no longer replays a resumed thread's messages into the chat context. on_chat_resume and persisted message loading now run at most once per session.
- Reconnecting the same session skips
on_chat_resumeand re-adding persisted messages. - A pending resume (for example, when the first socket disconnects before an interrupted
on_chat_resumecompletes) is finished on reconnect before the session is treated as live. - Resume delivery is retained across silent disconnects: initialized thread state stays pending until the receiving Socket.IO session is confirmed connected, and interaction metadata is re-emitted on the new socket.
- Concurrent reconnects wait for the in-progress resume instead of replaying it.
- Missing-thread errors are reported only once per session.
on_chat_startstill runs for restored sessions without a first interaction.- Adds regression tests for resume-once, pending-reconnect, concurrent-handler, and missing-thread cases.
Fixes #3061.