不为某个新特性,而是没道理把底座停在带并行 tool-result 缺陷的补丁版;2.0.3 是同线相邻补丁版,升级面窄、收益确定。承 tech-decisions §11-13「护城河进洋葱、 框架件谨慎审计」线。 代码:两 worker requirements 钉 2.0.3+溯源注;4 个 cheap-worker patch 的版本 guard 更 2.0.3——主控逐一源码核实 2.0.3 锚点仍成立:compress_context@_agent.py:259 未漂移 / _parse_stream_response@_openai_chat/_model.py:297·index 分桶:417 未漂移 / list_tools@_local_workspace.py:660 / get_toolkit 装配点迁 _chat.py:354(patch 替 绑定名不依赖行号);patch 头 pin 声明同步 2.0.3+复核标记,根因 2.0.2 期实证保留。 文档:current-truth 面扫除(agentscope-2.0-facts 改掉一处「2.0.3 是笔误」错陈述+ 行号漂移开源码更新 594→622/136→162/33→42/857→884/875→902、tech-decisions §15 升级决策散文、运行时 SoT 当前选型句、活代码注释、tier2 README 死链修);留痕层 (plans/HANDOFF/patch 根因分析/ADR 历史核验句)按两层纪律不动。 兼容三证:源码逐处 diff(RedisMessageBus/OpenAI formatter 零变化、Anthropic formatter 仅并行 tool-result bug 修、ModelCallEndEvent 无变化、MiddlewareBase 加性 get_middleware_key)/ cheap 393+tier2 140+patch 20 测试全绿 / dev 两 venv 升级后 3 服务健康。收敛真跑:cheap 便宜档 ReAct 全链路 356 trace 零升级异常+ 真出游戏过九门 9/9;tier2 Anthropic 工具循环跑满 40 轮写 15 文件 gen.log/trace 零升级异常(decision=fix 属 tier2 生成质量、非升级回归)。 2.0.3 新增原生 ReplyBudgetControlMiddleware(历史反复核验 2.0.2 不存在的类)/ tool 级洋葱/RAG/mem0,列而不迁(自建 ¥ 两段式 fail-closed 硬闸是护城河,原生 token 软控替不了),follow-up 见 §15。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
56 lines
3.6 KiB
Python
56 lines
3.6 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.3;2026-07-06 自 2.0.2 升级复核】运行时 monkeypatch,绝不改 venv/site-packages 文件本体。
|
|
依赖两个契约,2.0.3 已复核仍成立:① _toolkit.py 的 get_toolkit 仍以 `workspace.list_tools()` 为内建来源
|
|
(_toolkit.py:112);② LocalWorkspace.list_tools 仍为 async 无参方法、返六内建(_local_workspace.py:660)。
|
|
test_ws_builtin_tools_patch 全绿。上方根因是 2.0.2 期 cutover 的生产实证,原样保留。此后再升级仍按此复核
|
|
上述两点并重跑该单测(版本漂移时 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.3":
|
|
# 版本漂移:响亮告警但仍应用(不应用 = 内建 Bash/Write 旁路写白名单,比契约漂移更危险)。
|
|
print(
|
|
f"[ws-builtin-patch] WARNING: agentscope 版本 {ver} != 钉住的 2.0.3,"
|
|
"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.3 原签名一致(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.3,升级必须复核)。",
|
|
flush=True,
|
|
)
|