mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-21 16:18:55 +00:00
fix: salvage follow-up — remove redundant coercion, fix classifier, restore None guard
1. Remove PR's redundant strip_think_blocks coercion (Teknium's fix
296494db0 already handles this at the same chokepoint with superior
logic that drops thinking/reasoning blocks).
2. Restore 'if not content: return ' guard at top of strip_think_blocks
that was lost during cherry-pick auto-merge. Without it, None content
hits str(None) → 'None' string instead of returning empty.
3. Fix error classifier design flaw: remove 'conversation_loop' and
'run_agent' from _local_processing_modules — these are the container
modules for the try/except, so every exception passes through them,
making _hit_local always True and misclassifying transient API/network
errors as non-retryable local bugs.
4. Move module sets to module-level frozenset constants (_LOCAL_PROCESSING_MODULES,
_API_CALL_MODULES) instead of rebuilding on every exception.
5. Replace traceback.extract_tb() with raw tb walk — avoids disk I/O for
source lines that are never used.
6. Remove unused 'import traceback'.
7. Fix docstring corruption: 3 lines where think tags were replaced
with Chinese characters during the PR's editing.
This commit is contained in:
parent
7942a77586
commit
bd3d16a490
2 changed files with 30 additions and 35 deletions
|
|
@ -643,16 +643,16 @@ def strip_think_blocks(agent, content: str) -> str:
|
|||
"""Remove reasoning/thinking blocks from content, returning only visible text.
|
||||
|
||||
Handles four cases:
|
||||
1. Closed tag pairs (`` 执教… ``) — the common path when
|
||||
1. Closed tag pairs (`` <think>… ``) — the common path when
|
||||
the provider emits complete reasoning blocks.
|
||||
2. Unterminated open tag at a block boundary (start of text or
|
||||
after a newline) — e.g. MiniMax M2.7 / NIM endpoints where the
|
||||
closing tag is dropped. Everything from the open tag to end
|
||||
of string is stripped. The block-boundary check mirrors
|
||||
``gateway/stream_consumer.py``'s filter so models that mention
|
||||
`` 执教`` in prose aren't over-stripped.
|
||||
`` <think>`` in prose aren't over-stripped.
|
||||
3. Stray orphan open/close tags that slip through.
|
||||
4. Tag variants: `` 执教``, ``<thinking>``, ``<reasoning>``,
|
||||
4. Tag variants: `` <think>``, ``<thinking>``, ``<reasoning>``,
|
||||
``<REASONING_SCRATCHPAD>``, ``<thought>`` (Gemma 4), all
|
||||
case-insensitive.
|
||||
|
||||
|
|
@ -670,21 +670,6 @@ def strip_think_blocks(agent, content: str) -> str:
|
|||
after punctuation and carries a ``name="..."`` attribute) so prose
|
||||
mentions like "Use <function> in JavaScript" are preserved.
|
||||
"""
|
||||
# Defensive coercion: callers may pass multimodal content-parts lists
|
||||
# (e.g. after vision turns or context compaction). Extract any text
|
||||
# blocks and drop non-text parts before running regexes.
|
||||
if isinstance(content, list):
|
||||
parts = []
|
||||
for part in content:
|
||||
if isinstance(part, str):
|
||||
parts.append(part)
|
||||
elif isinstance(part, dict) and part.get("type") == "text":
|
||||
text = part.get("text")
|
||||
if isinstance(text, str):
|
||||
parts.append(text)
|
||||
content = "\n".join(parts)
|
||||
elif not isinstance(content, str):
|
||||
content = str(content) if content is not None else ""
|
||||
if not content:
|
||||
return ""
|
||||
# Coerce non-string content to text before any regex runs. Providers
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import re
|
|||
import ssl
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
import uuid
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
|
|
@ -79,6 +78,25 @@ logger = logging.getLogger(__name__)
|
|||
# to treat it as cancellation metadata rather than assistant prose.
|
||||
INTERRUPT_WAITING_FOR_MODEL_PREFIX = "Operation interrupted: waiting for model response ("
|
||||
|
||||
# Modules that indicate a deterministic local processing error when they
|
||||
# appear in an exception traceback WITHOUT any API-call module. Used by the
|
||||
# outer-loop error classifier to avoid retrying bugs that will fail
|
||||
# identically every time (e.g. TypeError from passing list content into a
|
||||
# regex helper). IMPORTANT: do NOT include "conversation_loop" or
|
||||
# "run_agent" here — those are the container modules for the try/except
|
||||
# itself, so every exception passes through them, which would make
|
||||
# _hit_local always True and misclassify transient API/network errors as
|
||||
# non-retryable local bugs. (#66267)
|
||||
_LOCAL_PROCESSING_MODULES = frozenset({
|
||||
"agent_runtime_helpers",
|
||||
"message_content",
|
||||
"message_sanitization",
|
||||
"chat_completion_helpers", # only local when NOT also an API-call module
|
||||
})
|
||||
_API_CALL_MODULES = frozenset({
|
||||
"chat_completion_helpers",
|
||||
})
|
||||
|
||||
|
||||
def _image_error_max_dimension(error: Exception) -> Optional[int]:
|
||||
"""Extract a provider-reported image dimension ceiling, if present."""
|
||||
|
|
@ -5609,23 +5627,15 @@ def run_conversation(
|
|||
# local post-processing helpers and never entered the interruptible
|
||||
# API-call helpers, it is almost certainly a local processing bug.
|
||||
# (#66267)
|
||||
_local_processing_modules = {
|
||||
"agent_runtime_helpers",
|
||||
"conversation_loop",
|
||||
"message_content",
|
||||
"run_agent",
|
||||
}
|
||||
_api_call_modules = {
|
||||
"chat_completion_helpers",
|
||||
}
|
||||
tb_module_names: set[str] = set()
|
||||
_tb = e.__traceback__
|
||||
while _tb is not None:
|
||||
_fname = os.path.splitext(os.path.basename(_tb.tb_frame.f_code.co_filename))[0]
|
||||
tb_module_names.add(_fname)
|
||||
_tb = _tb.tb_next
|
||||
|
||||
tb_stack = traceback.extract_tb(e.__traceback__)
|
||||
tb_module_names = {
|
||||
os.path.splitext(os.path.basename(frame.filename))[0]
|
||||
for frame in tb_stack
|
||||
}
|
||||
_hit_local = bool(tb_module_names & _local_processing_modules)
|
||||
_hit_api = bool(tb_module_names & _api_call_modules)
|
||||
_hit_local = bool(tb_module_names & _LOCAL_PROCESSING_MODULES)
|
||||
_hit_api = bool(tb_module_names & _API_CALL_MODULES)
|
||||
|
||||
_is_local_processing_error = _hit_local and not _hit_api
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue