|
19 | 19 |
|
20 | 20 | from copy import deepcopy |
21 | 21 | from functools import wraps |
| 22 | +import hashlib |
22 | 23 | import inspect |
23 | 24 | import json |
24 | 25 | import re |
|
47 | 48 | from agentrun.toolset import ToolSet |
48 | 49 | from agentrun.utils.log import logger |
49 | 50 |
|
| 51 | +# Tool name constraints for external providers like OpenAI |
| 52 | +MAX_TOOL_NAME_LEN = 64 |
| 53 | +TOOL_NAME_HEAD_LEN = 32 |
| 54 | + |
| 55 | + |
| 56 | +def normalize_tool_name(name: str) -> str: |
| 57 | + """Normalize a tool name to fit provider limits. |
| 58 | +
|
| 59 | + If `name` length is <= MAX_TOOL_NAME_LEN, return it unchanged. |
| 60 | + Otherwise, return the first TOOL_NAME_HEAD_LEN characters + md5(full_name) |
| 61 | + (32 hex chars), resulting in a 64-char string. |
| 62 | + """ |
| 63 | + if not isinstance(name, str): |
| 64 | + name = str(name) |
| 65 | + if len(name) <= MAX_TOOL_NAME_LEN: |
| 66 | + return name |
| 67 | + digest = hashlib.md5(name.encode("utf-8")).hexdigest() |
| 68 | + return name[:TOOL_NAME_HEAD_LEN] + digest |
| 69 | + |
50 | 70 |
|
51 | 71 | class ToolParameter: |
52 | 72 | """工具参数定义 |
@@ -253,7 +273,9 @@ def __init__( |
253 | 273 | args_schema: Optional[Type[BaseModel]] = None, |
254 | 274 | func: Optional[Callable] = None, |
255 | 275 | ): |
256 | | - self.name = name |
| 276 | + # Normalize tool name to avoid external provider limits (e.g. OpenAI 64 chars) |
| 277 | + # If name length > 64, keep first 32 chars and append 32-char md5 sum of full name. |
| 278 | + self.name = normalize_tool_name(name) |
257 | 279 | self.description = description |
258 | 280 | self.parameters = list(parameters or []) |
259 | 281 | self.args_schema = args_schema or _build_args_model_from_parameters( |
@@ -982,6 +1004,8 @@ def tool( |
982 | 1004 |
|
983 | 1005 | def decorator(func: Callable) -> Tool: |
984 | 1006 | tool_name = name or func.__name__ |
| 1007 | + # ensure tool name is normalized |
| 1008 | + tool_name = normalize_tool_name(tool_name) |
985 | 1009 | tool_description = description or ( |
986 | 1010 | func.__doc__.strip() if func.__doc__ else "" |
987 | 1011 | ) |
@@ -1362,6 +1386,7 @@ def wrapper(**kwargs): |
1362 | 1386 |
|
1363 | 1387 | # 设置函数属性(清理特殊字符,确保是有效的 Python 标识符) |
1364 | 1388 | clean_name = re.sub(r"[^0-9a-zA-Z_]", "_", tool_name) |
| 1389 | + clean_name = normalize_tool_name(clean_name) |
1365 | 1390 | wrapper.__name__ = clean_name |
1366 | 1391 | wrapper.__qualname__ = clean_name |
1367 | 1392 | if parameters: |
|
0 commit comments