refactor(agent): drop legacy '...[truncated]' tail from pruned-arg detector

The legacy tail check was a bare substring classifier with no producer
anchoring: the compressor on main only emits ' ...[truncated]' for
user-message/summary text, never for tool-call arguments, so any
effectful call whose content legitimately ends in '...[truncated]'
(e.g. writing docs or tests about truncation) would be refused. Keep
only the producer-shaped ⟪HERMES-CONTEXT-COMPRESSION⟫ marker regex.

Compile the regex once via a cached helper instead of per call. The
import stays lazy because agent.context_compressor -> prompt_builder ->
tool_dispatch_helpers would make a module-level import circular.

Co-authored-by: Kevin Rajan <7121943+kvnloo@users.noreply.github.com>
This commit is contained in:
kshitijk4poor
2026-09-24 14:01:10 +05:30
committed by kshitij
parent 30b6074802
commit b8a1bf759e

View File

@@ -9,6 +9,7 @@ normalisation, and the tool-result message constructor with untrusted-content wr
from __future__ import annotations
import functools
import json
import logging
import os
@@ -68,9 +69,19 @@ _DESTRUCTIVE_PATTERNS = re.compile(
# Output redirects that overwrite files (> but not >>)
_REDIRECT_OVERWRITE = re.compile(r'[^>]>[^>]|^>[^>]')
# Legacy compressor builds ended long string leaves with these ambiguous tails.
# Keep the compatibility guard narrow: real historical rewrites had a 200-char head.
_LEGACY_CONTEXT_PRUNED_ARG_TAILS = ("...[truncated]", "…[truncated]")
@functools.lru_cache(maxsize=1)
def _context_pruned_marker_re() -> re.Pattern[str]:
"""Producer-shaped regex for the compressor's model-visible prune marker.
Imported lazily: ``agent.context_compressor`` -> ``agent.prompt_builder`` ->
this module, so a module-level import would be circular. Compiled once.
"""
from agent.context_compressor import _COMPRESSION_MARKER_PREFIX
return re.compile(
re.escape(_COMPRESSION_MARKER_PREFIX)
+ r"\s+\d[\d,]* of \d[\d,]* chars omitted here by Hermes's context compressor\."
)
def _context_pruned_argument_paths(tool_name: str, args: Any) -> list[str]:
@@ -85,22 +96,12 @@ def _context_pruned_argument_paths(tool_name: str, args: Any) -> list[str]:
if not tool_may_have_side_effect(tool_name):
return []
# Late import keeps this helper from making the dispatch module own a second
# copy of the compressor sentinel (and avoids a heavy import at CLI startup).
from agent.context_compressor import _COMPRESSION_MARKER_PREFIX
marker_re = re.compile(
re.escape(_COMPRESSION_MARKER_PREFIX)
+ r"\s+\d[\d,]* of \d[\d,]* chars omitted here by Hermes's context compressor\."
)
marker_re = _context_pruned_marker_re()
found: list[str] = []
def _walk(value: Any, path: str) -> None:
if isinstance(value, str):
stripped = value.rstrip()
if marker_re.search(value) or (
len(stripped) > 200 and stripped.endswith(_LEGACY_CONTEXT_PRUNED_ARG_TAILS)
):
if marker_re.search(value):
found.append(path)
return
if isinstance(value, dict):