Skip to content

[Bug]: Tool-loop guardrails miss loops where args vary but the result never changes (incl. repeated multimodal results) #60084

Description

@Vissirexa

Bug Description

The tool-loop guardrails (agent/tool_guardrails.py) key their repetition tracking on the tool-call signature (tool name + canonical args) or on classified failure. Two loop shapes slip through both:

  1. Varying-args / fixed-result loop. A tool call that "succeeds" with different arguments on every call but keeps returning the same blocked/empty/error-page body. For ex. execute_code wrapping a web fetch against a source that consistently 404s or soft-blocks a scraper. The exact-failure counter never fires (failed is false), and the _no_progress tracker is keyed by signature and scoped to an idempotent-tool allowlist, so it never sees the loop either.
  2. Repeated multimodal results. A vision tool result of shape {"_multimodal": True, "content": [...]} embeds a base64 image payload, so str(result) is unique on every call even when the meaningful content (a placeholder caption like "Image loaded into your context") is identical. Repetition is never detected.

Observed running a local model (qwen3.6-35b) in unattended/gateway sessions: one session burned its iteration budget re-fetching the same blocked page with slightly different arguments; another re-loaded the same image via a vision tool 6 times with zero guard activity.

Steps to Reproduce

  1. Enable tool-loop guardrails (defaults are fine; optionally hard_stop_enabled: true).
  2. Have the agent call a tool that returns the same substantial error/blocked-page body regardless of arguments (e.g. fetch a URL that always serves the same 404/soft-block page), with the model varying the query args each attempt.
  3. Watch the loop run past every configured threshold with no warning appended to the tool results.
  4. Variant: have the agent load the same image via a vision/multimodal tool repeatedly - same outcome.

Expected Behavior

After N calls returning substantially identical content, the guardrails should treat it like the other repetition axes: append a soft warning to the tool result, and (when hard_stop_enabled) halt the loop at a higher threshold.

Actual Behavior

No guard fires at any point; the loop only ends when the iteration budget runs out.

Affected Component

Agent Core (conversation loop, context compression, memory)

Messaging Platform (if gateway-related)

No response

Debug Report

Not attaching "hermes debug share" links for this one: it's a code-level behavior
gap in agent/tool_guardrails.py, fully reproducible from unit tests and not
environment-specific, and my recent logs contain private gateway-session content.
Confirmed the gap still exists on current main by inspection — there is no
repetition tracking keyed on result content, only on call signature and
classified failure. Happy to share specific redacted log excerpts on request.

System info (from "hermes debug share --local"):

version:      0.18.0 (2026.7.1)
os:           Darwin 25.4.0 arm64 (macOS 15, Apple Silicon)
python:       3.11.15
openai_sdk:   2.24.0
provider:     lmstudio (local OpenAI-compatible endpoint)
model:        Qwen3.6-35B-A3B-MLX-8bit
toolsets:     hermes-cli
memory:       built-in
gateway:      telegram

Operating System

macOS 15

Python Version

3.11.15

Hermes Version

0.18.0

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

No response

Proposed Fix (optional)

No response

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havebugcomp/agentCore agent runtime: loop, agent_init, prompt builder, context-compression, responses endpointtype/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions