diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index ba2922771a076..47de9313bf6d3 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -869,10 +869,7 @@ def generate_launchd_plist() -> str: KeepAlive - - SuccessfulExit - - + StandardOutPath {log_dir}/gateway.log diff --git a/run_agent.py b/run_agent.py index 13278d94c04d3..3b9c9a3be3ecc 100644 --- a/run_agent.py +++ b/run_agent.py @@ -7917,13 +7917,36 @@ def _stop_spinner(): self._response_was_previewed = True break - # No fallback available — this is a genuine empty response. + # No fallback available — check if the model used a + # structured reasoning field (reasoning_content) for its + # answer. Thinking models (Kimi K2.5, DeepSeek-R1, etc.) + # consistently put their full response there and leave + # content empty. Retrying won't change that behavior — + # use the reasoning immediately instead of wasting API calls. + reasoning_text = self._extract_reasoning(assistant_message) + if reasoning_text and ( + getattr(assistant_message, 'reasoning_content', None) + or getattr(assistant_message, 'reasoning', None) + ): + self._vprint(f"{self.log_prefix}ℹ️ Thinking model returned response in reasoning field — using directly.") + final_response = reasoning_text + empty_msg = { + "role": "assistant", + "content": final_response, + "reasoning": reasoning_text, + "finish_reason": finish_reason, + } + messages.append(empty_msg) + if hasattr(self, '_empty_content_retries'): + self._empty_content_retries = 0 + break + + # Genuine empty response (no structured reasoning field). # Retry in case the model just had a bad generation. if not hasattr(self, '_empty_content_retries'): self._empty_content_retries = 0 self._empty_content_retries += 1 - - reasoning_text = self._extract_reasoning(assistant_message) + self._vprint(f"{self.log_prefix}⚠️ Response only contains think block with no content after it") if reasoning_text: reasoning_preview = reasoning_text[:500] + "..." if len(reasoning_text) > 500 else reasoning_text @@ -7931,7 +7954,7 @@ def _stop_spinner(): else: content_preview = final_response[:80] + "..." if len(final_response) > 80 else final_response self._vprint(f"{self.log_prefix} Content: '{content_preview}'") - + if self._empty_content_retries < 3: self._vprint(f"{self.log_prefix}🔄 Retrying API call ({self._empty_content_retries}/3)...") continue