fix(agent): continue ollama glm truncation replies
This commit is contained in:
64
run_agent.py
64
run_agent.py
@@ -2103,6 +2103,59 @@ class AIAgent:
|
||||
content = re.sub(r'</?(?:think|thinking|reasoning|thought|REASONING_SCRATCHPAD)>\s*', '', content, flags=re.IGNORECASE)
|
||||
return content
|
||||
|
||||
@staticmethod
|
||||
def _has_natural_response_ending(content: str) -> bool:
|
||||
"""Heuristic: does visible assistant text look intentionally finished?"""
|
||||
if not content:
|
||||
return False
|
||||
stripped = content.rstrip()
|
||||
if not stripped:
|
||||
return False
|
||||
if stripped.endswith("```"):
|
||||
return True
|
||||
return stripped[-1] in '.!?:)"\']}。!?:)】」』》'
|
||||
|
||||
def _is_ollama_glm_backend(self) -> bool:
|
||||
"""Detect the narrow backend family affected by Ollama/GLM stop misreports."""
|
||||
model_lower = (self.model or "").lower()
|
||||
provider_lower = (self.provider or "").lower()
|
||||
if "glm" not in model_lower and provider_lower != "zai":
|
||||
return False
|
||||
if "ollama" in self._base_url_lower or ":11434" in self._base_url_lower:
|
||||
return True
|
||||
return bool(self.base_url and is_local_endpoint(self.base_url))
|
||||
|
||||
def _should_treat_stop_as_truncated(
|
||||
self,
|
||||
finish_reason: str,
|
||||
assistant_message,
|
||||
messages: Optional[list] = None,
|
||||
) -> bool:
|
||||
"""Detect conservative stop->length misreports for Ollama-hosted GLM models."""
|
||||
if finish_reason != "stop" or self.api_mode != "chat_completions":
|
||||
return False
|
||||
if not self._is_ollama_glm_backend():
|
||||
return False
|
||||
if not any(
|
||||
isinstance(msg, dict) and msg.get("role") == "tool"
|
||||
for msg in (messages or [])
|
||||
):
|
||||
return False
|
||||
if assistant_message is None or getattr(assistant_message, "tool_calls", None):
|
||||
return False
|
||||
|
||||
content = getattr(assistant_message, "content", None)
|
||||
if not isinstance(content, str):
|
||||
return False
|
||||
|
||||
visible_text = self._strip_think_blocks(content).strip()
|
||||
if not visible_text:
|
||||
return False
|
||||
if len(visible_text) < 20 or not re.search(r"\s", visible_text):
|
||||
return False
|
||||
|
||||
return not self._has_natural_response_ending(visible_text)
|
||||
|
||||
def _looks_like_codex_intermediate_ack(
|
||||
self,
|
||||
user_message: str,
|
||||
@@ -9038,6 +9091,17 @@ class AIAgent:
|
||||
finish_reason = stop_reason_map.get(response.stop_reason, "stop")
|
||||
else:
|
||||
finish_reason = response.choices[0].finish_reason
|
||||
assistant_message = response.choices[0].message
|
||||
if self._should_treat_stop_as_truncated(
|
||||
finish_reason,
|
||||
assistant_message,
|
||||
messages,
|
||||
):
|
||||
self._vprint(
|
||||
f"{self.log_prefix}⚠️ Treating suspicious Ollama/GLM stop response as truncated",
|
||||
force=True,
|
||||
)
|
||||
finish_reason = "length"
|
||||
|
||||
if finish_reason == "length":
|
||||
self._vprint(f"{self.log_prefix}⚠️ Response truncated (finish_reason='length') - model hit max output tokens", force=True)
|
||||
|
||||
Reference in New Issue
Block a user