mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-09-03 17:52:00 +03:00
fix(tool_hints): respect max_length for plain (non-path/non-command) tool values
Plain tool values (grep patterns, web_search/x_search queries, find_files
globs) were never truncated by format_tool_hints(), so long arguments
overflowed tool_hint_max_length and were pushed to chat/UI verbatim.
Add a hard-truncation fallback for the plain branch, mirroring the existing
truncation used by abbreviate_path / _abbreviate_command. This completes the
same class of fix started in 99209a80 for is_path tools.
Adds 4 regression tests to tests/agent/test_tool_hint.py.
This commit is contained in:
committed by
Xubin Ren
parent
816a999cac
commit
eddfa0dd6b
@@ -104,6 +104,10 @@ def _fmt_known(tc: ToolCallRequest, fmt: ToolFormat, max_length: int = 40) -> st
|
||||
val = abbreviate_path(val, max_len=max_length)
|
||||
elif fmt[3]: # is_command
|
||||
val = _abbreviate_command(val, max_len=max_length)
|
||||
elif len(val) > max_length:
|
||||
# Plain values (grep patterns, search queries, ...) have no path or
|
||||
# command structure to fold, so fall back to a hard truncation.
|
||||
val = val[:max_length - 1] + "\u2026"
|
||||
return fmt[1].format(val)
|
||||
|
||||
|
||||
|
||||
@@ -303,6 +303,43 @@ class TestToolHintMaxLength:
|
||||
long = _hint([_tc("list_dir", {"path": long_path})], max_length=120)
|
||||
assert len(long) > len(short)
|
||||
|
||||
def test_plain_value_tools_respect_max_length(self):
|
||||
"""Plain-value tools must truncate like the is_path/is_command branches.
|
||||
|
||||
grep, web_search, x_search and find_files carry no path or command
|
||||
structure to fold, so their raw value used to reach the progress hint
|
||||
untruncated: a 400-char search query produced a 400-char hint.
|
||||
"""
|
||||
for name, key in (
|
||||
("grep", "pattern"),
|
||||
("web_search", "query"),
|
||||
("x_search", "query"),
|
||||
("find_files", "query"),
|
||||
):
|
||||
short = _hint([_tc(name, {key: "x" * 400})], max_length=40)
|
||||
long = _hint([_tc(name, {key: "x" * 400})], max_length=120)
|
||||
assert len(long) > len(short), name
|
||||
# Longest template is 'search X "{}"' — 12 chars of overhead.
|
||||
assert len(short) <= 40 + 12, name
|
||||
assert "\u2026" in short, name
|
||||
|
||||
def test_plain_value_short_value_untouched(self):
|
||||
"""Values inside the budget must not gain an ellipsis."""
|
||||
result = _hint([_tc("grep", {"pattern": "TODO|FIXME"})], max_length=40)
|
||||
assert result == 'grep "TODO|FIXME"'
|
||||
|
||||
def test_plain_value_exactly_at_max_length_untouched(self):
|
||||
"""A value exactly at max_length already fits."""
|
||||
query = "a" * 40
|
||||
result = _hint([_tc("web_search", {"query": query})], max_length=40)
|
||||
assert result == f'search "{query}"'
|
||||
assert "\u2026" not in result
|
||||
|
||||
def test_plain_value_one_over_max_length_truncates(self):
|
||||
"""One character over the budget truncates instead of overflowing."""
|
||||
result = _hint([_tc("grep", {"pattern": "a" * 41})], max_length=40)
|
||||
assert result == 'grep "' + "a" * 39 + "\u2026" + '"'
|
||||
|
||||
|
||||
class TestToolHintMalformedCalls:
|
||||
"""Malformed tool calls must not crash hint formatting (see HKUDS/nanobot)."""
|
||||
|
||||
Reference in New Issue
Block a user