mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
fix(orchestrator): use descriptive suffixes for duplicate tool names
Instead of opaque _1, _2 suffixes, derive meaningful labels from hardcoded defaults (e.g. search_topic_sports) so the LLM can distinguish tool variants by name. Falls back to numeric suffixes when defaults don't provide a useful label.
This commit is contained in:
@@ -259,12 +259,36 @@ def get_pending_tool_calls(conversation_history: list[Any] | None) -> dict[str,
|
|||||||
return {call_id: count for call_id, count in pending_calls.items() if count > 0}
|
return {call_id: count for call_id, count in pending_calls.items() if count > 0}
|
||||||
|
|
||||||
|
|
||||||
|
def _derive_suffix_from_defaults(defaults: dict[str, Any]) -> str:
|
||||||
|
"""Derive a short, descriptive suffix from hardcoded defaults.
|
||||||
|
|
||||||
|
Returns a cleaned string like ``_topic_sports`` derived from the first
|
||||||
|
default's key and value, giving the LLM a meaningful hint about how
|
||||||
|
this tool variant differs from its siblings. Falls back to ``""`` if
|
||||||
|
no usable label can be derived.
|
||||||
|
"""
|
||||||
|
if not defaults:
|
||||||
|
return ""
|
||||||
|
key, val = next(iter(defaults.items()))
|
||||||
|
# Use the value as a label when it's a short string; otherwise use the key.
|
||||||
|
if isinstance(val, str) and 1 <= len(val) <= 30:
|
||||||
|
label = f"{key}_{val}"
|
||||||
|
else:
|
||||||
|
label = key
|
||||||
|
# Sanitise to [a-zA-Z0-9_] and trim
|
||||||
|
label = re.sub(r"[^a-zA-Z0-9]+", "_", label).strip("_").lower()
|
||||||
|
return f"_{label}" if label else ""
|
||||||
|
|
||||||
|
|
||||||
def _disambiguate_tool_names(tools: list[dict[str, Any]]) -> None:
|
def _disambiguate_tool_names(tools: list[dict[str, Any]]) -> None:
|
||||||
"""Ensure all tool names are unique (Anthropic API requires this).
|
"""Ensure all tool names are unique (Anthropic API requires this).
|
||||||
|
|
||||||
When multiple nodes use the same block type, they get the same tool name.
|
When multiple nodes use the same block type, they get the same tool name.
|
||||||
This appends _1, _2, etc. and enriches descriptions with hardcoded defaults
|
This derives a descriptive suffix from hardcoded defaults (e.g.
|
||||||
so the LLM can distinguish them. Mutates the list in place.
|
``search_topic_sports``) so the LLM can distinguish tool variants by name.
|
||||||
|
Falls back to numeric suffixes (``_1``, ``_2``) when defaults don't
|
||||||
|
provide a useful label. Also enriches descriptions with the full
|
||||||
|
pre-configured values. Mutates the list in place.
|
||||||
|
|
||||||
Malformed tools (missing ``function`` or ``function.name``) are silently
|
Malformed tools (missing ``function`` or ``function.name``) are silently
|
||||||
skipped so the caller never crashes on unexpected input.
|
skipped so the caller never crashes on unexpected input.
|
||||||
@@ -301,13 +325,27 @@ def _disambiguate_tool_names(tools: list[dict[str, Any]]) -> None:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
counters[name] = counters.get(name, 0) + 1
|
counters[name] = counters.get(name, 0) + 1
|
||||||
# Skip suffixes that collide with existing (e.g. user-named) tools
|
|
||||||
while True:
|
# Try a descriptive suffix first; fall back to numeric.
|
||||||
suffix = f"_{counters[name]}"
|
desc_suffix = _derive_suffix_from_defaults(defaults)
|
||||||
candidate = f"{name[: 64 - len(suffix)]}{suffix}"
|
if desc_suffix:
|
||||||
if candidate not in taken:
|
candidate = f"{name[: 64 - len(desc_suffix)]}{desc_suffix}"
|
||||||
break
|
if candidate in taken:
|
||||||
counters[name] += 1
|
# Descriptive suffix collided — append counter to de-dup
|
||||||
|
num_suffix = f"{desc_suffix}_{counters[name]}"
|
||||||
|
candidate = f"{name[: 64 - len(num_suffix)]}{num_suffix}"
|
||||||
|
else:
|
||||||
|
candidate = None
|
||||||
|
|
||||||
|
if not candidate or candidate in taken:
|
||||||
|
# Pure numeric fallback
|
||||||
|
while True:
|
||||||
|
suffix = f"_{counters[name]}"
|
||||||
|
candidate = f"{name[: 64 - len(suffix)]}{suffix}"
|
||||||
|
if candidate not in taken:
|
||||||
|
break
|
||||||
|
counters[name] += 1
|
||||||
|
|
||||||
func["name"] = candidate
|
func["name"] = candidate
|
||||||
taken.add(candidate)
|
taken.add(candidate)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user