dsh-python-only:强制 DSHM 端侧使用 Python 工具

前言

DeepSeek Harness(DSH)的 Agent 在端侧执行代码时,若混用 bash 等外部 shell,会引入环境不一致、权限风险和不可控的副作用。在 HarmonyOS 设备上,端侧 bash 跑在 guest 虚拟机中,且该虚拟机里没有 python3,使得脚本编写与调试变得复杂。为解决这一问题,需要把端侧一切代码执行与数据处理都统一到 python 工具上,同时禁止 shell 类工具。

yinghan-123/dsh-python-only 是一个 DSH 插件,通过提示词约束与工具守卫两层机制,强制 Agent 在端侧使用 python 工具,并拦截所有 shell 类工具调用。端侧的 python 工具跑在宿主进程内的内嵌 CPython 3.12 中,不依赖 guest VM,从而实现稳定且可预测的执行环境。

是什么

  • 定位:DSH 插件,强制 Agent 在 DSHM 端侧一切代码执行与数据处理使用 python 工具,并拦截 shell 类工具。
  • 维护者:yinghan-123。
  • 分类:工作流。
  • 核心目标:消除端侧环境不一致,提升 Agent 行为的可预测性与稳定性。

核心功能

插件通过两层约束同时生效:

层 机制 效果
提示词 systemPrompt.section(app:python-only)+ 每步动态提醒(app:python-only-reminder) 模型在第一次思考时就知道必须用 python,并知道运行时边界
守卫 tools.guard() 同步拦截 模型若仍调用 bash / pwsh / terminal_*,调用被直接拒绝(结果 Error: …),文案指向改用 python

守卫是单调的:一旦拒绝,没有任何插件能重新放行该次调用。

设置界面

设置 → 侧栏「强制 Python」(客户端半部 lib/client.js 注册 settings.section,order 26)。页面内容如下:

控件 作用
开关 总开关;关闭后提示词仍生效、但不再拦截工具
拦截工具列表 逗号/换行分隔的工具名,默认 bash、pwsh、terminal_open/send/read/signal/close/list
保存 / 恢复默认 写入 profile 行并立即生效

实现要点:

  • 客户端半部必须由包自己的浏览器 bundle 注册独立设置页,不依赖官方插件 UI。
  • 数据通道走平台公开面:ctx.configForms.get("python-only") 拿表单 scope,getSnapshot()/subscribe() 读、set()/unset() 写。
  • host 半部的 Config 字段都标了 volatile(),写入经 settings 服务落回 profile 行、再由 cosmokit 的 volatile 引用原地更新运行中的实例 —— 设置页保存后无需重启。
  • 平台模块(react、primitives)全部 optional,缺 React 时退化为 inert 渲染。

不做什么

  • 不提供 python 工具本身。端侧由 @deepseek-ai/dshm-tool-python 提供;桌面端由 DSH 自带 python 工具提供。
  • 不拦 read / glob / grep / web_fetch / web_search / 子代理等非执行类工具。
  • 没有命令白名单:git、pnpm、构建命令同样被拦(刻意选择——端侧 bash 不可靠,与其半开不如全关)。
  • 不写持久化状态:配置就是 profile 行里的 config。

安装与启用

一行安装(DSHM 端侧)

一行安装命令如下:

pnpm add github.com/yinghan-123/dsh-python-only

安装后需要重启 DSHM 一次才会挂载(profile 的 patchReload 是 startup)。

手动部署

需要手动部署或精确控制文件落位时,需确保以下位置就位:

  1. 包:把本目录整体复制到 profile 的 node_modules:
   <DSH_HOME>/profiles/ondevice/node_modules/dsh-python-only/

(DSH_HOME 本机是 /data/storage/el2/base/haps/entry/files/dsh/home。)

  1. bundle 声明:profiles/ondevice/package.json 里
   "dependencies": { "dsh-python-only": "1.0.0" },
   "dsh": { "profile": { "bundles": [ "...", "dsh-python-only" ] } }

(行由包自带的 cordis.patch.yml 插入,不依赖会被种子重建的 dshm-user-rows 用户区。)

  1. 配置覆盖行(让设置页能读到该行):profiles/ondevice/cordis.patch.yml 的用户行区之外加
   - id: python-only
     name: dsh-python-only
     config:
       enabled: true
       blockedTools:
         - bash
         - pwsh
         - terminal_open
         - terminal_send
         - terminal_read
         - terminal_signal
         - terminal_close
         - terminal_list
  1. 重启 DSHM 一次(profile 的 patchReload 是 startup;客户端 bundle 也只在启动时被 dsh-client-modules 扫描)。

停用 / 回滚

  • 临时放行 shell:设置页关掉开关(立即生效)。
  • 完全停用:package.json 的 bundles 里去掉 dsh-python-only(或给行加 disabled: true),重启。
  • 彻底移除:删 node_modules/dsh-python-only/、bundles/dependencies 条目与那行 config,重启。

验证清单

  1. 设置侧栏出现「强制 Python」页,开关与列表可编辑,保存后立即生效。
  2. Agent 调 bash → 返回 Error: 本环境强制使用 python 工具:\bash` 已被 python-only 插件禁用…`。
  3. Agent 用 python 跑代码 → 正常返回。
  4. 系统提示里出现「# 强制 Python 工具(python-only)」段。

兼容性与依赖

  • DSH 版本:>=0.2.0-rc.1 <0.3.0-0。运行时校验字段是 package.json 的 engines.dsh(dsh-app-boot 只读这个;dsh.compatibility 仅作元数据)。
  • 依赖:@deepseek-ai/schemastery(Config schema);tools.guard()、systemPrompt.section/context() 为 0.2.x 公开 API。
  • 客户端声明:dsh.client: { platform: "web", inject: ["@deepseek-ai/dsh-client-ui-settings"] },由 dsh-client-modules 通过 exports["./client"] 加载。

文件结构

dsh-python-only/
├── package.json        # bundle patch + client 声明 + engines.dsh
├── cordis.patch.yml    # 插入 - id: python-only / name: dsh-python-only
├── lib/index.js        # host:提示词 section/reminder + tools.guard + volatile Config
├── lib/client.js       # 浏览器:设置 →「强制 Python」页(settings.section)
└── README.md

适用场景与注意

  • 适合需要端侧行为稳定、避免 shell 脚本环境差异的场景。
  • 插件以当前 dsh 进程权限运行,安装前应检查源码与许可证。

小结

yinghan-123/dsh-python-only 通过提示词约束与工具守卫两层机制,强制 DSHM 端侧 Agent 一切代码执行与数据处理使用 python 工具,并拦截所有 shell 类工具调用。它不提供 python 工具本身,只负责策略与守卫,适合对端侧执行环境稳定性有较高要求的场景。

目录页 | GitHub 仓库

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye