fix: surface exhausted empty model responses - #23505
Open
taivu1998 wants to merge 1 commit into
Open
Conversation
taivu1998
marked this pull request as ready for review
May 11, 2026 03:46
teknium1
reviewed
Jul 13, 2026
teknium1
left a comment
Contributor
There was a problem hiding this comment.
Thanks for addressing the exhausted-empty response path. The user-visible raw-sentinel symptom has since been superseded on current main: agent/turn_finalizer.py:299-326 replaces (empty) with an actionable explanation, with end-to-end coverage in tests/run_agent/test_turn_completion_explainer.py:142-163.
Problems
- The PR edits the old post-loop implementation in
run_agent.py; current main runs these post-response effects fromagent/turn_finalizer.py:337-480, so the patch needs a non-mechanical port. - Current main still passes the generated explanation to hooks and external-memory sync (
agent/turn_finalizer.py:343-378,462-478), and the CLI still permits auto-title/TTS (cli.py:12542-12560,12705-12708). This means the side-effect-suppression objective remains relevant, but it must be keyed from the turn-exit reason/metadata rather than the old raw sentinel.
Suggested changes
- Preserve current main's visible explanation, add exhausted-empty metadata from
empty_response_exhausted, and use it to gate the affected integrations and CLI title/TTS paths.
Automated hermes-sweeper review.
| @@ -15025,7 +15035,8 @@ def _stop_spinner(): | |||
| # Fired once per turn after the tool-calling loop completes. | |||
Contributor
There was a problem hiding this comment.
Current main's live post-loop path is now agent/turn_finalizer.py, and it replaces (empty) with a user-facing explanation before hooks run. Please port this predicate there using turn_exit_reason == "empty_response_exhausted"; preserving the old raw-sentinel condition would not cover the current execution path.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
empty_response_exhaustedmetadata when the agent exhausts empty-response retriesfinal_response == "(empty)"sentinel for compatibility while preventing hooks, external memory sync, background reviews, CLI titles, and TTS from treating it as a real assistant answer(empty)sentinelRoot Cause
Issue #17248 reports sessions that appear to complete with a literal
(empty)answer after tool calls or empty model responses. The agent already had retry and cleanup scaffolding, but the terminal sentinel was indistinguishable from meaningful assistant content to downstream surfaces such as plugin hooks, memory sync, title generation, TTS, and CLI display.Fix
This PR preserves the existing sentinel return value for compatibility, but marks the exhausted-empty path with explicit result metadata:
empty_response_exhausted: trueerror_code: "empty_response_exhausted"errorstringThe agent then gates post-response integrations on a meaningful-final-response check, while the CLI normalizes exhausted sentinel results into a helpful visible error message.
Validation
HERMES_HOME=/private/tmp/hermes-agent-17248-publish-home-focused ./scripts/run_tests.sh tests/run_agent/test_run_agent.py -k "empty_response or replayed_tool_history"- 8 passedHERMES_HOME=/private/tmp/hermes-agent-17248-publish-home-adjacent ./scripts/run_tests.sh tests/run_agent/test_empty_response_recovery_persistence.py tests/run_agent/test_message_sequence_repair.py tests/cli/test_empty_response_display.py- 18 passedHERMES_HOME=/private/tmp/hermes-agent-17248-publish-home-full ./scripts/run_tests.sh tests/run_agent/test_run_agent.py- 326 passeduv run ruff check run_agent.py cli.py tests/run_agent/test_run_agent.py tests/cli/test_empty_response_display.py- passedgit diff --check- passedFixes #17248