From 18a2078ebbff9512f2762b51e895b421380df329 Mon Sep 17 00:00:00 2001 From: Frank Song Date: Mon, 6 Jul 2026 08:38:08 +0800 Subject: [PATCH] fix(streaming): guard empty terminal error hints --- api/streaming.py | 6 ++- ..._issue5121_provider_auth_terminal_error.py | 38 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/api/streaming.py b/api/streaming.py index 4829a5c3..6eeb3892 100644 --- a/api/streaming.py +++ b/api/streaming.py @@ -8675,9 +8675,13 @@ def _run_agent_streaming( _snapshot_and_append_partial_on_error(s, stream_id) except Exception: logger.debug("Failed to snapshot partials on error for %s", stream_id, exc_info=True) + _error_content = ( + f'**{_err_label}:** {_error_payload.get("message") or _err_label}' + + (f'\n\n*{_err_hint}*' if _err_hint else '') + ) _error_message = { 'role': 'assistant', - 'content': f'**{_err_label}:** {_error_payload.get("message") or _err_label}\n\n*{_err_hint}*', + 'content': _error_content, 'timestamp': int(time.time()), '_error': True, } diff --git a/tests/test_issue5121_provider_auth_terminal_error.py b/tests/test_issue5121_provider_auth_terminal_error.py index b3332dbc..877c62bd 100644 --- a/tests/test_issue5121_provider_auth_terminal_error.py +++ b/tests/test_issue5121_provider_auth_terminal_error.py @@ -455,6 +455,44 @@ def test_non_auth_silent_failure_still_uses_no_response(tmp_path, monkeypatch): assert saved.messages[-1]["_error"] is True +def test_live_settlement_empty_hint_does_not_append_empty_emphasis(tmp_path, monkeypatch): + session = _prepare_session( + "empty_hint_failure", + "stream_empty_hint_failure", + pending_user_message="Please fail plainly", + ) + + class EmptyHintFailureAgent(MockAgent): + def run_conversation(self, **kwargs): + return { + "status": "failed", + "messages": list(kwargs.get("conversation_history") or []), + "error": "synthetic hard failure", + } + + fake_queue = _run_stream( + monkeypatch, + session, + "stream_empty_hint_failure", + EmptyHintFailureAgent, + workspace=str(tmp_path), + ) + saved = Session.load("empty_hint_failure") + assert saved is not None + + events = _queue_events(fake_queue) + apperrors = [data for event, data in events if event == "apperror"] + assert apperrors, "expected apperror for generic terminal failure" + assert apperrors[-1]["type"] == "error" + assert apperrors[-1].get("hint") in (None, "") + + error_content = saved.messages[-1]["content"] + assert saved.messages[-1]["_error"] is True + assert error_content == "**Error:** synthetic hard failure" + assert "\n\n**" not in error_content + assert not error_content.endswith("**") + + def test_completed_assistant_answer_with_stale_partial_flag_settles_done(tmp_path, monkeypatch): session = _prepare_session( "completed_answer_stale_partial",