Skip malformed-args validation when auto-heal is on

The F3 pre-dispatch validator flagged any non-object tool-call
``arguments`` as malformed, even when the caller had set
``auto_heal_tool_calls=True``. The dispatcher downstream already
heals bare-string arguments (for example a raw web_search query)
into a valid ``{"query": ...}`` shape, so rejecting them up front
made the validation loop fight the heal and effectively disabled
the auto-heal feature for that family of models.

Gate the malformed-args branch on ``auto_heal_tool_calls`` being
off so dispatch keeps its existing healing semantics. The
unknown-tool branch still fires in either mode because no amount
of healing can invent a tool that is not registered.

Existing tests in tests/test_validation_retry_loop.py already pin
both paths (``test_malformed_args_bypassed_when_heal_on`` and
``test_malformed_args_caught_when_heal_off``); both pass with this
change.
This commit is contained in:
Daniel Han 2026-05-22 15:49:30 +00:00
commit 828f89abbe

View file

@ -5020,6 +5020,15 @@ class LlamaCppBackend:
# tool-result tied to the hallucinated call id and
# re-enter the model. Skips when the budget is spent so
# the existing error path still runs.
#
# ``malformed_args`` (non-object arguments) only fires
# when auto-heal is OFF. With auto_heal_tool_calls=True
# the dispatch path downstream coerces bare-string
# arguments (e.g. a raw web_search query) into a valid
# `{"query": ...}` shape, and rejecting those calls
# here would defeat the heal. The unknown-tool branch
# still runs in either mode because no amount of
# healing can invent a tool that isn't registered.
_validation_problem = None
if (
tool_calls
@ -5032,6 +5041,10 @@ class LlamaCppBackend:
if _vname not in _allowed_tool_names:
_validation_problem = ("unknown_tool", _vtc, _vname)
break
if auto_heal_tool_calls:
# Dispatch will heal non-object arguments; do
# not pre-empt it by rejecting them here.
continue
_vraw = _vfn.get("arguments", "")
if isinstance(_vraw, str):
try: