mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-26 03:30:36 +00:00
Stage 318: PR #1856 — fix: preserve pending turn during stale cleanup by @ai-ag2026
This commit is contained in:
+7
-1
@@ -675,6 +675,7 @@ def _clear_stale_stream_state(session) -> bool:
|
||||
with _get_session_agent_lock(session.session_id):
|
||||
if getattr(session, "active_stream_id", None) != stream_id:
|
||||
return False
|
||||
_materialize_pending_user_turn_before_error(session)
|
||||
session.active_stream_id = None
|
||||
if hasattr(session, "pending_user_message"):
|
||||
session.pending_user_message = None
|
||||
@@ -1508,7 +1509,12 @@ from api.workspace import (
|
||||
_workspace_blocked_roots,
|
||||
)
|
||||
from api.upload import handle_upload, handle_upload_extract, handle_transcribe
|
||||
from api.streaming import _sse, _run_agent_streaming, cancel_stream
|
||||
from api.streaming import (
|
||||
_sse,
|
||||
_run_agent_streaming,
|
||||
cancel_stream,
|
||||
_materialize_pending_user_turn_before_error,
|
||||
)
|
||||
from api.providers import get_providers, get_provider_quota, set_provider_key, remove_provider_key
|
||||
from api.onboarding import (
|
||||
apply_onboarding_setup,
|
||||
|
||||
@@ -366,6 +366,40 @@ def test_stream_error_pending_materialization_does_not_duplicate_eager_checkpoin
|
||||
assert [m.get("role") for m in s.messages].count("user") == 1
|
||||
|
||||
|
||||
def test_stale_stream_cleanup_materializes_pending_turn_before_clearing_state():
|
||||
"""A zombie/stale stream repair must preserve the pending user prompt.
|
||||
|
||||
If the process dies after chat_start saved pending_user_message but before the
|
||||
agent merges the user turn, /api/session stale cleanup must not clear that
|
||||
pending field without first appending a durable user message.
|
||||
"""
|
||||
from api.routes import _clear_stale_stream_state
|
||||
|
||||
sid = "test_pending_error_d3_stale"
|
||||
s = _make_session(
|
||||
session_id=sid,
|
||||
pending_msg="please make the GUI fully usable",
|
||||
messages=[{"role": "assistant", "content": "previous answer"}],
|
||||
)
|
||||
s.pending_started_at = 1778187755.0
|
||||
s.pending_attachments = [{"name": "visible-state.png"}]
|
||||
# No matching STREAMS entry: this simulates a dead worker/server restart.
|
||||
|
||||
cleared = _clear_stale_stream_state(s)
|
||||
|
||||
assert cleared is True
|
||||
assert s.active_stream_id is None
|
||||
assert s.pending_user_message is None
|
||||
assert s.messages[-1]["role"] == "user"
|
||||
assert s.messages[-1]["content"] == "please make the GUI fully usable"
|
||||
assert s.messages[-1]["timestamp"] == 1778187755
|
||||
assert s.messages[-1]["attachments"] == [{"name": "visible-state.png"}]
|
||||
|
||||
reloaded = models.get_session(sid, metadata_only=False)
|
||||
assert reloaded.messages[-1]["role"] == "user"
|
||||
assert reloaded.messages[-1]["content"] == "please make the GUI fully usable"
|
||||
|
||||
|
||||
# ── Structural guard: pin call sites of the materialize helper at error branches ──
|
||||
|
||||
def test_materialize_helper_called_immediately_before_error_path_clears():
|
||||
|
||||
Reference in New Issue
Block a user