mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-14 04:02:26 +00:00
fix: prevent stale reasoning from being reused across turns
The reasoning-box extraction loop in run_conversation() walked backwards through the entire message history looking for any assistant message with a non-empty 'reasoning' field. When the current turn produced no reasoning (e.g. the provider returned reasoning_content=null for a trivial response), the loop walked past the current turn and showed reasoning from a prior turn — stale text from minutes or hours ago displayed as if it belonged to the current reply. Fix: stop the walk at the user message that started the current turn. That picks the most recent reasoning WITHIN the turn (correct for tool-calling turns where reasoning lands on the tool-call step and the final-answer step has reasoning=None — common on Claude thinking, DeepSeek v4, Codex Responses), and returns None cleanly when the current turn genuinely had no reasoning. Co-authored-by: happy5318 <happy5318@users.noreply.github.com>
This commit is contained in:
parent
4577f392f9
commit
efe1cb00c8
1 changed files with 11 additions and 1 deletions
12
run_agent.py
12
run_agent.py
|
|
@ -13952,9 +13952,19 @@ class AIAgent:
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.warning("post_llm_call hook failed: %s", exc)
|
logger.warning("post_llm_call hook failed: %s", exc)
|
||||||
|
|
||||||
# Extract reasoning from the last assistant message (if any)
|
# Extract reasoning from the CURRENT turn only. Walk backwards
|
||||||
|
# but stop at the user message that started this turn — anything
|
||||||
|
# earlier is from a prior turn and must not leak into the reasoning
|
||||||
|
# box (confusing stale display; #17055). Within the current turn
|
||||||
|
# we still want the *most recent* non-empty reasoning: many
|
||||||
|
# providers (Claude thinking, DeepSeek v4, Codex Responses) emit
|
||||||
|
# reasoning on the tool-call step and leave the final-answer step
|
||||||
|
# with reasoning=None, so picking only the last assistant would
|
||||||
|
# silently drop legitimate same-turn reasoning.
|
||||||
last_reasoning = None
|
last_reasoning = None
|
||||||
for msg in reversed(messages):
|
for msg in reversed(messages):
|
||||||
|
if msg.get("role") == "user":
|
||||||
|
break # turn boundary — don't cross into prior turns
|
||||||
if msg.get("role") == "assistant" and msg.get("reasoning"):
|
if msg.get("role") == "assistant" and msg.get("reasoning"):
|
||||||
last_reasoning = msg["reasoning"]
|
last_reasoning = msg["reasoning"]
|
||||||
break
|
break
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue