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