Files
agent/langgraph_qwen/validators.py
2025-08-30 23:29:26 +08:00

68 lines
2.1 KiB
Python

import re
import hashlib
from typing import Iterable, List, Tuple, Any
TOOL_NAME_PATTERN = re.compile(r"^[a-zA-Z0-9_-]{1,64}$")
class ToolValidationError(Exception):
pass
def sanitize_tool_name(name: str, max_len: int = 64) -> str:
safe = re.sub(r"[^a-zA-Z0-9_-]", "_", name or "tool")
if len(safe) > max_len:
suffix = hashlib.sha1(safe.encode()).hexdigest()[:8]
safe = safe[: max_len - 9] + "_" + suffix
return safe or "tool"
def _find_illegal_chars(name: str) -> List[str]:
return sorted(list(set(re.findall(r"[^a-zA-Z0-9_-]", name))))
def _get_name(obj: Any) -> str:
return getattr(obj, "name", None) or getattr(obj, "tool_name", None) or getattr(obj, "__name__", "tool")
def validate_tool_names(
tools: Iterable[Any], *, strict: bool = True, max_len: int = 64
) -> Tuple[bool, List[str]]:
"""
Validate that tool names conform to OpenAI-compatible constraints:
- Allowed chars: a-z, A-Z, 0-9, underscore, hyphen
- Max length: 64
Returns (ok, messages). If strict=True and invalid tools exist,
raises ToolValidationError with a detailed report.
"""
messages: List[str] = []
errors: List[str] = []
for idx, t in enumerate(tools):
name = _get_name(t)
if TOOL_NAME_PATTERN.match(name or ""):
continue
parts: List[str] = [f"{idx}个工具名称不合法: '{name}'"]
if not name:
parts.append("原因: 为空")
else:
illegal = _find_illegal_chars(name)
if illegal:
parts.append(f"包含非法字符: {''.join(illegal)} (仅允许[a-zA-Z0-9_-])")
if len(name) > max_len:
parts.append(f"长度超限: {len(name)} > {max_len}")
suggestion = sanitize_tool_name(name or "tool", max_len=max_len)
parts.append(f"建议名称: '{suggestion}'")
errors.append("; ".join(parts))
if errors:
report = "\n".join(errors)
messages.append(report)
if strict:
raise ToolValidationError(report)
return False, messages
return True, messages