fix(subagent): refuse the disabled backend tools instead of only hiding them - #1001
Open
rafaelasor wants to merge 1 commit into
Open
fix(subagent): refuse the disabled backend tools instead of only hiding them#1001rafaelasor wants to merge 1 commit into
rafaelasor wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
变更说明
先说明利益关系:我维护开源的智能体委派库 attenu-guard
(github.com/attenu-io/attenu-guard),是在为它测试 handoff 时发现这个问题的。本补丁是
原生实现,没有用到它。
默认审批模式把
write_file、edit_file、execute从子智能体隐藏,避免子智能体绕过主线程的逐项审批。但隐藏只作用于
bind_tools:create_agent_filesystem_middleware仍把七个文件工具全部注册进子智能体的 ToolNode,且子智能体不构造审批中间件,所以同名调用仍会执行。
本改动让“隐藏”等于“关闭”:
create_agent_filesystem_middleware增加disabled_tools参数,被禁用的工具根本不注册。_SubAgentToolFilterMiddleware增加wrap_tool_call/awrap_tool_call,在工具体执行前对被禁用的名字返回
status="error"的ToolMessage,提示模型把结果交回主智能体。本改动直接影响权限与模型可见输入,按决策记录规范属于非平凡变更。改动小而完整、没有待裁决
的替代方案,因此没有先提 proposed;如维护者认为需要,我补一份
docs/develop-guides/decisions/implemented/2026-09-07-subagent-tool-enforcement.md。(English) Interest first: I maintain attenu-guard, an open-source agent-delegation library
(github.com/attenu-io/attenu-guard), and found this while testing handoffs for it. This
patch is native and does not use it.
Default approval mode hides
write_file,edit_fileandexecutefrom subagents so theycannot bypass the main thread's per-call approval. The hide applies at
bind_toolsonly,while
create_agent_filesystem_middlewareregisters all seven filesystem tools in thesubagent's ToolNode and the subagent builds no approval middleware, so a call naming one of
the three still runs.
This change makes the hide mean disabled. The middleware takes a
disabled_toolsset anddoes not register those tools.
_SubAgentToolFilterMiddlewaregainswrap_tool_call/awrap_tool_call, which return aToolMessagewithstatus="error"before the body runs.This changes permissions and model-visible input, so it is non-trivial under the decision
record rules. It is small and self-contained with no open alternative, so I did not file a
proposed record first. I will add an implemented record if you want one.
验证情况
新增六个测试用例(
test/unit/agents/test_subagent_tool_filter.py)。在我本机pytest test/unit -m "not slow" --ignore=test/unit/test_live_api_cleanup.py从 1800 通过变为 1806 通过(在
fd0d9c4f上;在当前maine460fad6上同样全部通过,排除了新增的test/unit/performance目录,它在我的环境中无法收集,与本改动无关)。排除那个文件是因为在我使用的 Homebrew Python 下,标准库的test包遮蔽了backend/test,该文件收集失败,与本改动无关。另外运行了
python3 scripts/verify_engineering_contracts.py(通过:77 decisions /5 workflows / 4 agents files / 126 docs / 26 routers / 241 web sources)与
python3 -m unittest scripts.test_verify_engineering_contracts(61 tests, OK)。integration 与 e2e 未运行:本机没有起 Docker Compose 拓扑。
(English) Six test cases are added. Locally
pytest test/unit -m "not slow" --ignore=test/unit/test_live_api_cleanup.pygoes from 1800to 1806 passed; I exclude that file because the stdlib
testpackage shadowsbackend/testunder my Homebrew Python, which is unrelated to this change. I also ran
python3 scripts/verify_engineering_contracts.py(passes) andpython3 -m unittest scripts.test_verify_engineering_contracts(61 tests, OK). I did notrun integration or e2e; I had no Docker Compose topology up.
影响与风险
always_trust行为不变:_disabled_tools_for("always_trust")仍然只返回present_artifacts、ask_user_question、install_skill,所以那些敏感 backend 工具在该模式下照常注册、照常可调用。default 模式下的行为变化是刻意的:被隐藏的工具从“可执行”变为
“执行前被拒绝”。
(English)
always_trustis unchanged:_disabled_tools_for("always_trust")still returnsonly
present_artifacts,ask_user_questionandinstall_skill, so the sensitive backendtools stay registered and callable there. The behaviour change in default mode is the
intended one: a hidden tool goes from executable to refused before its body runs.
界面与关联事项
不涉及界面。
Closes #1000(English) No UI.
Closes #1000