55 lines
3.4 KiB
Python
55 lines
3.4 KiB
Python
"""ws_builtin_tools_patch.py — 便宜档 Service 关 workspace 内建工具(Bash/Edit/Glob/Grep/Read/Write)。
|
|
|
|
【坐实根因(2026-07-04 cutover S2 生产实证)】agentscope 2.0.2 Service 路 build_toolkit
|
|
(app/_service/_toolkit.py:107)把 workspace.list_tools() 的六内建(workspace/_local_workspace.py
|
|
:670-679 硬编码,无配置开关)无条件并入 agent 工具面,再拼 extra_agent_tools(便宜档六工具)。后果两条:
|
|
① 写边界击穿:便宜档护城河 = 六工具白名单(write 越界拒 + basename L1_FIXED 拒,I1 fail-closed),
|
|
内建 Write/Edit/Bash 不走白名单、可写工作区任意路径(Bash 甚至可越 workdir 触仓外)——白名单被旁路;
|
|
② 失败噪声/死圈:内建 Bash cwd=Service 工作区(非 repo 根),M3 惯性用相对路径 `ls game-runtime/...`
|
|
连败(80009 四连败触旧版退化签名 stuck 熔断 ¥2.6 作废;80011 复现同款失败指纹,签名富化打印抓获)。
|
|
CLI 路(cheap_run)从来只有六工具;Service 归并(配置控制面阶段一②)带进了这个面,per-task review
|
|
未抓到,live 工具失败观测抓获——「跨路径封口」教训再 +1(tech-decisions §12 同款)。
|
|
|
|
【修法】cheap Service 进程内 monkeypatch LocalWorkspace.list_tools → 返回 []。作用域正确性:本进程
|
|
(cheap_service_app)只跑便宜档 agent,进程内全局补丁 = 恰好全体便宜档 agent;tier2 服务是独立进程,
|
|
不受影响。skills/MCP 装载(list_skills / MCP 发现)不动;Planning/Team/Schedule 工具面收窄另评
|
|
(工单 h;其成本风险已有 ¥ 两段式硬地板兜上界)。
|
|
|
|
【钉 agentscope==2.0.2,升级必须复核此补丁】运行时 monkeypatch,绝不改 venv/site-packages 文件本体。
|
|
依赖两个 2.0.2 契约:① _toolkit.py build_toolkit 以 `workspace.list_tools()` 为内建来源;
|
|
② LocalWorkspace.list_tools 为 async 无参方法。升级 agentscope 后必须复核上述两点并重跑
|
|
tests/test_ws_builtin_tools_patch.py(版本漂移时 apply 响亮 warning、但仍应用——不应用等于开着白名单旁路)。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
def apply_ws_builtin_tools_patch() -> None:
|
|
"""把 LocalWorkspace.list_tools 换成恒返回空表(便宜档 Service 进程专用,幂等)。"""
|
|
import agentscope # noqa: PLC0415
|
|
from agentscope.workspace import LocalWorkspace # noqa: PLC0415
|
|
|
|
ver = getattr(agentscope, "__version__", "?")
|
|
if ver != "2.0.2":
|
|
# 版本漂移:响亮告警但仍应用(不应用 = 内建 Bash/Write 旁路写白名单,比契约漂移更危险)。
|
|
print(
|
|
f"[ws-builtin-patch] WARNING: agentscope 版本 {ver} != 钉住的 2.0.2,"
|
|
"list_tools 契约可能已变,升级复核未做——补丁仍应用,请尽快复核。",
|
|
flush=True,
|
|
)
|
|
|
|
if getattr(LocalWorkspace.list_tools, "_cheap_ws_patched", False):
|
|
return # 幂等:重复 apply 不再包一层
|
|
|
|
async def _no_builtin_tools(self): # noqa: ANN001 —— 与 2.0.2 原签名一致(async 无参)
|
|
# 便宜档:内建工具全关(写边界只认六工具白名单;根因与作用域见模块头注释)。
|
|
return []
|
|
|
|
_no_builtin_tools._cheap_ws_patched = True # type: ignore[attr-defined]
|
|
LocalWorkspace.list_tools = _no_builtin_tools
|
|
print(
|
|
"[ws-builtin-patch] 已关 workspace 内建工具(Bash/Edit/Glob/Grep/Read/Write)——"
|
|
"便宜档写边界只认六工具白名单(钉 2.0.2,升级必须复核)。",
|
|
flush=True,
|
|
)
|