跳到主要内容

dsh-stream-rules

已验证

@jiesou/dsh-stream-rules · v0.1.12 · MIT

Inject rules when needed, without wasting context. DSH port of opencode-stream-rules.

安装

dsh plugin add @jiesou/dsh-stream-rules

用 dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南。

源码

标签

说明文档

dsh-stream-rules

按需注入规则,不浪费上下文。

-6336866371853030306_121

你可以为 agent 编写自定义的流式规则(streaming rules)。

规则只在模式匹配后作为一条 steering notice 注入,然后 agent 会从同一个位置重试。 这样你就能控制 agent 的行为边界,同时不浪费上下文。

由我的 jiesou/opencode-stream-rules 移植到 DSH。 与 oh-my-pi 的 "Time-traveling stream rules" 类似,但代码实现非常简单紧凑。

工作原理

当规则的 match 返回 true 时触发,匹配对象是:

  • 工具调用 — 工具名 + 扁平化后的参数(数字也带上,比如 timeoutMs),在 dispatch 之前。
  • 落定的结果 — dispatch 之后,工具的内容、状态标记([timed out after 600000ms]、[exit code: 1] 等)和 error message 一起加入匹配,因此描述"结局"(崩溃、磁盘满、超时)的规则也能命中。dispatch 之后命中只能 steering、不能 deny。

命中后:

  • 默认 — 向 agent 注入一条 SYSTEM NOTICE steering 消息(dispatch 前用 agent.inject(),dispatch 后作为 additionalContexts 挂在工具结果上——都是 DSH 的"非唤醒"机制,为下一次 pre-step 排队模型可见上下文)。agent 会从同一位置重试,此时它已经知道了这条规则。
  • reject: true — 拒绝第一次工具调用({ kind: 'deny' });之后的尝试会被放行。在不至于过度限制的前提下进行 steering,例如在容器内已经允许 pip install 通过时。

每条规则在每个会话(每个 agent)中最多触发一次,与原始版本的 notified 去重逻辑一致。

安装

从 npm 安装(预构建产物,推荐):

dsh plugin --profile <name> add @jiesou/dsh-stream-rules

或从 GitHub 安装(安装时会运行 prepare 构建):

dsh plugin --profile <name> add github:jiesou/dsh-stream-rules

或者在你 profile 的 cordis.patch.yml 中添加一行:

- id: stream-rules
  name: '@jiesou/dsh-stream-rules'

安装之后

你需要自己编写 .js 规则文件。在编辑之前,这个插件默认不会做任何事。

  1. 找到插件的路径:
$DSH_HOME/profiles/<name>/node_modules/@jiesou/dsh-stream-rules

$DSH_HOME 默认是 ~/.dsh。

  1. 编写规则:
mv rules/rules.js.example rules/rules.local.js
  • 以 _ 开头的文件会被跳过。
  • 可以用 config.rules 指向其他规则目录:
- id: stream-rules
  name: '@jiesou/dsh-stream-rules'
  config:
    rules: /path/to/your/rules
  • 带 reject: true 的规则只在第一次工具调用时拒绝;之后 agent 重试会被放行。既做了引导又不过度限制(例如在容器里时允许 pip install)。

编写规则

// rules/rules.local.js
export default [
  {
    match: (v) =>
      v.includes('pip') &&
      v.includes('install') &&
      !v.includes('uv pip') &&
      !v.includes('uvx'),
    reject: true,
    prompt: 'Use `uvx` or `uv venv` + `uv pip` instead of `pip install` directly',
  },
  {
    match: (v) => v.includes('curl') && v.includes('api.github.com'),
    prompt: 'Prefer using `gh` cli over `curl https://api.github.com/...`. gh offers more requests limits.',
  },
  {
    match: (v) => v.includes('pdf'),
    prompt: 'Use the `markitdown` skill to read PDF files.',
  },
  // add your rules here
]
字段 必填 说明
match ✅ (v: string) => boolean;每次工具调用都会被扁平化为字符串并匹配——dispatch 之后还会带上落定结果的内容、标记与 error message
prompt ✅ 用于 steering 的提示语
reject 若为 true,则先阻止第一次工具调用,而不仅仅是 steering

兼容性

声明在 package.json 的 dsh.compatibility:DSH >=0.1.7-alpha.1 <0.2,Node.js ^22.19.0 || >=24.0.0,Profile web / headless。

>=0.1.7-alpha.1 是硬下限,不是偏好:该版本起 session format v4 拒绝已废弃的 { kind: 'plugin', plugin: … } 消息来源,插件改为自带 MessageSourceMap 条目。

逐版本证据(每个版本都用 dsh plugin add <tarball> 装进一次性 Profile):Profile 能组合并冷启动;再针对该版本的 tools/pre-execute waterfall 与 agent.inject() 直接验证工具调用钩子(steering 通知送达、reject: true 拒绝第一次调用并放行重试);最后卸载插件,Profile 仍能启动。下表是 >=0.1.0-rc.6 那次声明的证据;上面新声明的范围尚未逐版本重新实测。

DSH 版本 安装 启动 钩子 卸载
0.1.5-alpha.1 通过 通过 通过 通过
0.1.5-alpha.2 通过 通过 通过 通过
0.1.5-rc.1 通过 通过 通过 通过

实现说明

  • 单个 src/index.ts(约 80 行)。
  • 使用 DSH 的 tools/pre-execute waterfall(deny)、tools/post-execute(匹配失败报错 + additionalContexts)和 agent.inject()(steering),这些都是官方文档记载的原生扩展点。没有改动核心,没有 monkey-patching。