-
Notifications
You must be signed in to change notification settings - Fork 99
feature: 支持关闭skill_list_tools tool #323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,18 +80,24 @@ def __init__(self, | |
| runtime_tools: Optional[List[ToolABC]] = None, | ||
| skill_stager: Optional[Stager] = None, | ||
| skill_config: Optional[dict[str, Any]] = None, | ||
| excluded_tools: Optional[List[str]] = None, | ||
| **run_tool_kwargs: dict[str, Any]): | ||
| """Initialize the skill toolset. | ||
|
|
||
| Args: | ||
| paths: Optional list of skill paths. If None, will create a new one. | ||
| repository: Skill repository. If None, will be retrieved from context metadata. | ||
| enable_hot_reload: Whether to enable skill hot reload checks for | ||
| auto-created repositories. | ||
| repo_resolver: Skill repository resolver. If None, will use the default repository resolver. | ||
| workspace_runtime_resolver: Workspace runtime resolver. If None, will use the default workspace runtime resolver. | ||
| enable_hot_reload: Whether to enable skill hot reload checks for auto-created repositories. | ||
| tool_filter: Optional tool filter. If None, will include all tools. | ||
| is_include_all_tools: Optional flag to include all tools. If True, will include all tools. | ||
| user_tools: Optional list of user tools. If None, will not include any user tools. | ||
| run_tool_kwargs: Optional keyword arguments for skill run tool. If None, will use default values. | ||
| create_ws_name_cb: Optional workspace name callback. If None, will use the default workspace name callback. | ||
| runtime_tools: Optional list of runtime tools. If None, will use the default runtime tools. | ||
| skill_stager: Optional skill stager. If None, will use the default skill stager. | ||
| skill_config: Optional skill config. If None, will use the default skill config. | ||
| excluded_tools: Optional list of tools to exclude. If None, will not exclude any tools. | ||
| **run_tool_kwargs: Optional keyword arguments for skill run tool. If None, will use default values. | ||
| """ | ||
| super().__init__(tool_filter=tool_filter, is_include_all_tools=is_include_all_tools) | ||
| self.name = "skill_toolset" | ||
|
|
@@ -136,6 +142,8 @@ def __init__(self, | |
| WorkspaceWriteStdinTool(workspace_exec_tool), | ||
| WorkspaceKillSessionTool(workspace_exec_tool), | ||
| ] | ||
| self._excluded_tools: List[str] = excluded_tools or [] | ||
| self._default_tools: List[ToolABC] = [] | ||
|
|
||
| @property | ||
| def repository(self) -> BaseSkillRepository: | ||
|
|
@@ -152,9 +160,6 @@ async def get_tools(self, invocation_context: Optional[InvocationContext] = None | |
| Returns: | ||
| List of tools from all registered skills | ||
| """ | ||
| tools: List[ToolABC] = [] | ||
| skill_functions: List[SkillToolFunction] = SKILL_REGISTRY.get_all() | ||
| skill_functions.extend(self._function_tools) | ||
| if self._repo_resolver is not None: | ||
| repository = self._repo_resolver(invocation_context) | ||
| else: | ||
|
|
@@ -167,16 +172,35 @@ async def get_tools(self, invocation_context: Optional[InvocationContext] = None | |
| agent_context.with_metadata(SKILL_REPOSITORY_KEY, repository) | ||
| if not is_exist_skill_config(agent_context): | ||
| set_skill_config(agent_context, self._skill_config) | ||
| if self._default_tools: | ||
| return self._default_tools.copy() | ||
|
|
||
| tools: List[ToolABC] = [] | ||
| tools.append(self._load_tool) | ||
| tools.append(self._run_tool) | ||
| tools.append(self._exec_tool) | ||
| tools.extend(self._runtime_tools) | ||
| skill_functions: List[SkillToolFunction] = SKILL_REGISTRY.get_all() | ||
| skill_functions.extend(self._function_tools) | ||
| for skill_function in skill_functions: | ||
| try: | ||
| tools.append(FunctionTool(func=skill_function)) | ||
| except Exception as ex: # pylint: disable=broad-except | ||
| # Log error but continue loading other tools | ||
| logger.warning("Failed to get tools from skill '%s': %s", skill_function.__name__, ex) | ||
| continue | ||
|
|
||
| tools = self._exclude_tools(tools) | ||
| self._default_tools.extend(tools) | ||
|
Comment on lines
+175
to
+193
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 问题: 触发条件: 任意一次 实际影响: 后续所有请求持续返回旧列表:新注册的技能函数永远不会暴露给 LLM,已注销或被 修正方向: 为缓存增加失效条件(例如在 |
||
| return tools | ||
|
|
||
| def _exclude_tools(self, tools: List[ToolABC]) -> List[ToolABC]: | ||
| """Exclude tools from the list.""" | ||
| if not self._excluded_tools: | ||
| return tools | ||
| available_tools: List[ToolABC] = [] | ||
| for tool in tools: | ||
| name = getattr(tool, "name", None) | ||
| if not name or name in self._excluded_tools: | ||
| continue | ||
| available_tools.append(tool) | ||
| return available_tools | ||
|
Comment on lines
+196
to
+206
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 问题: 本次提交的核心功能—— 触发条件: 运行现有测试套件即可确认: 实际影响: 排除名称拼写错误、过滤逻辑回归(例如误删具有合法名称的工具)或缓存行为破坏都不会被测试发现;"支持关闭 skill_list_tools" 这一提交主目标本身处于未验证状态。 修正方向: 在 |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,18 +20,35 @@ | |
|
|
||
|
|
||
| def skill_list_tools(tool_context: InvocationContext, skill_name: str) -> dict[str, Any]: | ||
| """List callable tools declared for a skill. | ||
| """List tool names declared by a specific skill. | ||
|
|
||
| This only reports tools referenced by the selected skill. It does not list | ||
| every tool available to the agent. An empty result means that this skill | ||
| declares no tools; it does not mean that the agent has no tools available. | ||
|
|
||
| Args: | ||
| skill_name: The name of the skill to load. | ||
| skill_name: The name of the skill to inspect. | ||
|
|
||
| Returns: | ||
| Object containing available tools. | ||
| Object containing the tool names declared by this skill. | ||
| """ | ||
| repository: Optional[BaseSkillRepository] = tool_context.agent_context.get_metadata(SKILL_REPOSITORY_KEY) | ||
| if repository is None: | ||
| raise ValueError("repository not found") | ||
| skill = repository.get(skill_name) | ||
| if skill is None: | ||
| logger.error("Skill %s not found", repr(skill_name)) | ||
| return {"available_tools": []} | ||
| return {"available_tools": list(skill.tools or [])} | ||
| available_tools = [] | ||
| else: | ||
| available_tools = list(skill.tools or []) | ||
| return { | ||
| "skill_name": | ||
| skill_name, | ||
| "available_tools": | ||
| available_tools, | ||
|
Comment on lines
+42
to
+48
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 问题: 触发条件: LLM 或调用方传入拼写错误/不存在的 实际影响: 模型收到 修正方向: 在返回结构中区分两种情况,例如增加 |
||
| "scope": | ||
| "skill_declared_tools_only", | ||
| "note": | ||
| "Only tools declared by this skill are listed. " | ||
| "This does not represent all tools available to the agent.", | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
问题: 新增的
excluded_tools只在SkillToolSet.get_tools一层过滤工具,与SkillsRequestProcessor/SkillProfileFlags生成系统提示词引导的既有机制完全脱节,二者之间没有任何信息传递。触发条件: 用户按参数定义排除任何被引导文案点名的内置工具(例如
excluded_tools=["skill_run"]、["skill_select_tools"]或["skill_list_skills"]),同时 Agent 按示例标准接法设置了skill_repository,使SkillsRequestProcessor以默认fullprofile 注入引导。实际影响:
trpc_agent_sdk/agents/core/_skill_processor.py的_tooling_guidance_text与_default_full_tooling_and_workspace_guidance仍会指示 LLM 使用已被排除的工具(如 "Use the skill_select_tools tool..." 以及大量skill_run/skill_exec指引),LLM 随后调用不存在的工具,触发tool_not_found错误事件,浪费对话轮次甚至导致任务失败。变更前工具无法从工具集中移除,引导不会指向不存在的工具。修正方向: 将排除信息同步进技能配置/profile 机制,例如构造
SkillsRequestProcessor时从SkillToolSet读取excluded_tools并并入forbidden_tools/SkillProfileFlags解析,或在参数文档中明确excluded_tools仅适用于引导文案未点名的工具,保证引导与实际可用工具集一致。