hermes - ✅(Solved) Fix [Bug]: Gateway can reuse a stale reasoning block from a previous assistant turn [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#17500Fetched 2026-04-30 06:47:07
View on GitHub
Comments
1
Participants
2
Timeline
7
Reactions
0
Timeline (top)
labeled ×5commented ×1cross-referenced ×1

Error Message

No traceback or hard runtime error was involved.

The issue was user-visible on the gateway side: the displayed reasoning block could occasionally match the previous turn instead of the current one.

Root Cause

Root Cause Analysis (optional)

Fix Action

Fixed

PR fix notes

PR #17502: fix(gateway): avoid reusing stale reasoning blocks

Description (problem / solution / changelog)

Summary

Follow-up to #17500.

When gateway reasoning display is enabled, Hermes can sometimes show a stale 💭 Reasoning: block from a previous assistant turn instead of the current reply.

This PR fixes that by making last_reasoning come only from the latest assistant message, rather than walking backward until it finds any older assistant message with reasoning.

Root Cause

The visible gateway reasoning block is built from agent_result["last_reasoning"].

At the end of the main run path, run_agent.py currently walks backward through messages and picks the first assistant message with a truthy reasoning field.

That means if the latest assistant message has no reasoning payload, Hermes can keep walking backward and reuse reasoning from an earlier assistant turn.

gateway/run.py then prepends that stale value directly into the visible 💭 Reasoning: block, making it look like the current reply produced reasoning when it actually came from a previous turn.

Changes

FileChange
run_agent.pyChange last_reasoning extraction to inspect only the latest assistant message instead of reusing older assistant reasoning
tests/cli/test_reasoning_command.pyAdd regression coverage for the case where a previous assistant message has reasoning but the latest assistant message does not
gateway/run.pyImprove long reasoning collapse so the display shows both the start and end of long traces, which makes repeated Gemini-style reasoning preambles less misleading during debugging

Validation

CheckResult
/home/nanako/.hermes/hermes-agent/venv/bin/pytest -q tests/cli/test_reasoning_command.py -k 'reasoning_present or reasoning_none or picks_last_assistant or does_not_reuse_previous_reasoning_when_latest_assistant_has_none or empty_reasoning_treated_as_none'5 passed
/home/nanako/.hermes/hermes-agent/venv/bin/python -m py_compile run_agent.py gateway/run.pypassed

Repro / Effect

Before this patch:

  • one assistant turn could produce reasoning
  • a later assistant turn with no reasoning payload could still show the previous turn's reasoning block in the gateway
  • long reasoning blocks were also truncated to the first lines only, which made distinct traces look identical when they shared the same preamble

After this patch:

  • the gateway only shows reasoning from the latest assistant turn
  • a later assistant turn without reasoning no longer reuses an older reasoning block
  • long reasoning display includes both the beginning and end of the trace for easier debugging

Related #17500

Changed files

  • gateway/run.py (modified, +10/-3)
  • run_agent.py (modified, +9/-3)
  • tests/cli/test_reasoning_command.py (modified, +36/-10)

Code Example

Report   https://paste.rs/vrqtC
agent.log   https://dpaste.com/HKKERKWPJ
gateway.log   https://paste.rs/Gh963

---

No traceback or hard runtime error was involved.

The issue was user-visible on the gateway side: the displayed reasoning block could occasionally match the previous turn instead of the current one.

---

last_reasoning = None
for msg in reversed(messages):
    if msg.get("role") == "assistant" and msg.get("reasoning"):
        last_reasoning = msg["reasoning"]
        break
RAW_BUFFERClick to expand / collapse

Bug Description

When display.show_reasoning is enabled on the gateway, the visible 💭 Reasoning: block can sometimes repeat the previous assistant turn's reasoning instead of reflecting the current reply.

What happened:

  • one assistant turn produced a reasoning block
  • a later assistant turn replied normally but did not carry a fresh reasoning payload
  • the gateway still showed the older reasoning block from the previous assistant turn

What I expected instead:

  • the gateway should only display reasoning from the latest assistant turn
  • if the latest assistant message has no reasoning payload, it should not reuse an older one

Steps to Reproduce

  1. Run the Hermes gateway with display.show_reasoning: true.
  2. Use a gateway surface such as Discord.
  3. Send a prompt that produces a visible reasoning block.
  4. Send another prompt where the latest assistant reply completes normally but does not include a new reasoning payload.
  5. Observe that the gateway can display the previous turn's reasoning block again.

Expected Behavior

The reasoning block should correspond only to the latest assistant reply.

If the latest assistant message has no reasoning payload, Hermes should not fall back to an older assistant message's reasoning.

Actual Behavior

The gateway can show a stale reasoning block from an earlier assistant turn.

This makes the visible 💭 Reasoning: section look like it belongs to the current reply even when it was actually produced by a previous one.

Affected Component

Gateway (Telegram/Discord/Slack/WhatsApp)

Messaging Platform (if gateway-related)

Discord

Debug Report

Report   https://paste.rs/vrqtC
agent.log   https://dpaste.com/HKKERKWPJ
gateway.log   https://paste.rs/Gh963

Operating System

Ubuntu 24.04

Python Version

3.11.15

Hermes Version

v0.11.0 (2026.4.23)

Additional Logs / Traceback (optional)

No traceback or hard runtime error was involved.

The issue was user-visible on the gateway side: the displayed reasoning block could occasionally match the previous turn instead of the current one.

Root Cause Analysis (optional)

The bug is in run_agent.py in the last_reasoning extraction logic near the end of the main run path.

Current behavior walks backward through messages and selects the first assistant message with a truthy reasoning field:

last_reasoning = None
for msg in reversed(messages):
    if msg.get("role") == "assistant" and msg.get("reasoning"):
        last_reasoning = msg["reasoning"]
        break

That means if the latest assistant message has no reasoning payload, Hermes can continue walking backward and pick an older assistant message's reasoning instead.

gateway/run.py then prepends agent_result["last_reasoning"] directly into the visible 💭 Reasoning: block, so the stale reasoning becomes user-visible.

The correct behavior is to stop at the latest assistant message and only use its reasoning if that latest assistant message actually has one.

Proposed Fix (optional)

Change the last_reasoning extraction logic so it only inspects the latest assistant message.

If the latest assistant message has a non-empty reasoning field, use it. If the latest assistant message has no reasoning, keep last_reasoning = None and do not reuse an older assistant turn's reasoning block.

I also added a regression test for the case where a previous assistant message has reasoning but the latest assistant message does not.

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

extent analysis

TL;DR

Update the last_reasoning extraction logic in run_agent.py to only consider the latest assistant message's reasoning.

Guidance

  • Review the last_reasoning extraction logic in run_agent.py and modify it to stop at the latest assistant message.
  • Ensure that if the latest assistant message has no reasoning payload, last_reasoning remains None and an older assistant turn's reasoning is not reused.
  • Verify the fix by testing scenarios where the latest assistant message has and doesn't have a reasoning payload.
  • Consider adding regression tests to cover these scenarios, as proposed in the issue.

Example

last_reasoning = None
latest_assistant_msg = next((msg for msg in reversed(messages) if msg.get("role") == "assistant"), None)
if latest_assistant_msg and latest_assistant_msg.get("reasoning"):
    last_reasoning = latest_assistant_msg["reasoning"]

Notes

The proposed fix seems to address the issue, but it's essential to thoroughly test the updated logic to ensure it works as expected in all scenarios.

Recommendation

Apply the proposed workaround by updating the last_reasoning extraction logic, as it directly addresses the identified root cause and provides a clear solution to the problem.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING