@huiliyi37/dsh-plan-mode
v0.8.0
Published
Logged per-agent plan mode with deployment guidance, a direct slash command, and a user-reviewed exit
Readme
@huiliyi37/dsh-plan-mode
English | 中文
按 agent(智能体)分别记录到日志的 plan 协作状态,提供由部署方配置的引导内容、用于直接进入的 /plan [message] 命令、用于直接退出的 /plan off 命令,以及经用户评审的 exit_plan_mode 退出方式。Plan mode 是软引导;沙箱模式和批准策略仍是独立的强制执行维度。
持久状态
plan/mode({ active: boolean })是一个仅存在于日志中、每次以完整值替换的 SessionEventMap 成员。foldPlanMode(events) 返回最后记录的值,如果没有则返回 false,因此恢复、fork 和压缩(compaction)都能直接从会话日志恢复 plan 状态。UI 通过 session/event 观察已提交的切换。
plan/file({ path, heading })是它的 log-only 伴生事件:每次 exit_plan_mode 调用——无论批准还是继续规划——都会把提交的计划 markdown 落盘并记录位置。它从不进入模型面;它存在的意义是让已批准的计划在压缩之后仍可找回。
ctx.planMode.set(agent, active) 在 agent 空闲时立即提交——下一个 prompt 之前不会有任何边界到来,因此独立的 plan/mode 事件当场落账——在 agent 运行中则持有待生效选择,并等待下一个被接受的轮内 pre-step;返回值区分 committed、queued、表示反转的 cancelled 和 noop。get(agent) 返回 { active, pending? },将塑造当前步骤的日志状态与用户的轮中选择分开。初始与续步 pre-step 边界都在覆盖范围内;同一步骤的请求恢复重试会复用已冻结的 assembly,并将该选择保留到下一个 pre-step。当最后记录的请求头描述了另一状态时,用户选择的变更会贡献一条插件来源的 user/message 通知(两条提交路径皆然)。
模型与人类交互
激活时,已配置的 section 在每轮首次请求的消息尾部注入(绝不进入 system prompt),因此进入或退出 plan mode 保持缓存前缀字节恒定。插件始终注册 exit_plan_mode,使工具 schema 在转换期间保持稳定;其 execute 路径只接受已激活的 plan mode,且只有通过 ctx.userInteraction 获得用户明确批准后才退出。
plan mode 激活期间,一个单调的 ctx.tools.guard 守卫会在执行时拒绝变更工具族:write、edit、str_replace_editor(其 create/str_replace/insert 变异子命令)、git_commit、terminal_open/send/signal/close。拒绝是模型可见的工具错误,引导用只读工具探索并以 exit_plan_mode 提交;工具目录本身不变,schema 在模式切换间保持稳定。bash/pwsh 保持可用以支持只读 shell 探索(与 Claude Code 的 plan mode 语义一致);残余的 shell 写洞由正交的沙箱轴兜底,部署方可经 blockedTools 扩大封禁名单。守卫只读已落账状态——轮内待生效的进入不会打断当前轮的合法写——子代理会话 fold 自己的日志,约束不泄漏进子会话。
提交的计划同时会写到 $DSH_HOME/plans/<编码 cwd>/<会话 id>/<slug>.md(插件私有 node:fs 直写,不过 fs 沙箱,只读部署不会卡死评审),批准结果的渲染文本携带 path。
评审问题声明 plan-review 呈现意图,并指名 Approve 为表示批准的标签,因此有能力的 UI 会把计划呈现为一次决定而非通用问题;两种情况下该工具读到的回答完全相同。放弃审阅 —— 用户关掉请求改用说话 —— 会如实报告给模型,要求它留在 plan mode 中等待那条消息;其余每一种评审失败都保留 seam 自身的消息。
组合 ctx.commands 时,该包会注册 /plan [message],并将参数恰好为 off 的情况保留给直接退出。不带参数的 /plan 会启用 plan mode;任何其他非空参数都会先启用 plan mode,再通过 agent.steer() 提交,因此它会在 plan 引导下成为下一步骤的常规已记录用户消息。/plan off 会选择停用状态,不发送模型输入;它还可以在启用 plan mode 的待处理选择到达请求边界之前将其取消。该命令声明了 input.images:composer 图片附件会排在被 steer 消息的文本块之前。携带图片的无参 /plan 会 steer 一条仅含图片的用户消息;携带图片的 /plan off 会在任何模式变更之前直接返回错误,composer 因此保留这些图片。
Web 客户端使用该插件提供的 /plan 命令;其他入口可以直接驱动同一服务,无需定义第二套 mode 词汇。
会话投影
当组合挂载 ctx.sessionProjections(@huiliyi37/dsh-session-projection)时,本包会在一个注入的子插件中注册 plan 投影单元。名为 plan 且携带已记录 args 的 command/run 记录会开启一个候选目标状态(off → 未激活,其余 → 激活);与它配对的 command/done 会保留成功的选择、丢弃失败的选择;plan/mode 会提交已记录状态并清除被保留的选择。其他任何事件都返回同一个状态引用。view 推导 { active, pending },其中 pending 仅在未落定或已成功的选择与已记录状态不同时为 true。该值仍完全由日志回放得出,因此 host 重启、其他标签页和冷读都能仅凭日志恢复它,而被拒绝的带图片 /plan off 不会留下待生效的退出。key 由 src/types.ts 通过声明合并加入 SessionProjectionMap:host 消费方经 ./types 获取,client 聚合经 ./client 获取。框架负责驱动该单元,载体通过历史尾页和 session/projection 推送帧提供其值。未挂载注册表的组合不受影响。
配置
- id: plan-mode
name: '@huiliyi37/dsh-plan-mode'
config:
section: |
You are in plan mode. Explore and design before presenting the complete
plan through exit_plan_mode.
# blockedTools: [bash] # optional: extend the guard's deny listsection 必填且非空。blockedTools 可选,是在内置变更工具族之上追加封禁的工具名列表。出现未知键时,插件会加载失败。该包不接受任意命名的 mode、工具过滤器、沙箱设置或批准策略。
设计:plan 专用协作状态 · 硬只读守卫与计划文件 · 计划模式重定价缓存前缀。
模型体验
Plan 策略指导(请求尾部)
模型所见内容
Plan mode 激活时,模型会在每轮首次请求的最后一条消息中看到部署方提供的原样 section 文本;未激活 mode 不贡献文本。
配置示例
You are in plan mode. Explore and design before presenting the complete plan through exit_plan_mode.Token 影响
未激活 mode 不增加 token;mode 激活时,每轮(首个 step)只注入一次已配置的段落,而非每个请求。
KV Cache 影响
按构造为零:指导走请求尾部,进入或退出 plan mode 绝不改变 system prompt 或请求头——缓存前缀在转换期间保持字节恒定。
人类命令
模型所见内容
/plan、/plan off 及其终端结果留在模型历史之外。除恰好为 off 以外的非空后缀会在选择 plan mode 后,通过 agent.steer() 成为一条用户消息:composer 图片附件作为前导图片块,其后是去除首尾空白的文本块。携带图片的无参 /plan 会 steer 一条仅含这些图片块的用户消息。plan mode 已激活时,选择 /plan off 只会在最后一个请求头描述了 plan mode 的情况下追加标准的已记录用户切换通知;取消待生效进入不会贡献通知,因为没有请求观测到它。
Token 影响
可选消息的历史 token 成本与单独提交该内容相同。不携带图片的无参 /plan 和 /plan off 不增加 token;携带图片的无参 /plan 具有常规的图片提示词成本。退出已激活的 plan mode 时,如果记录了该转换,还会追加一条简短且会保留的切换通知。
KV Cache 影响
用户块是仅追加的对话增长。进入或退出 plan mode 不改变前缀中的任何内容;指导注入与切换通知都追加在可复用请求前缀之后。
退出工具 schema 与评审交互
模型所见内容
exit_plan_mode schema 在两种状态下均可用;在 plan mode 外执行会失败,而 plan mode 内经批准的评审会返回规范的 { approved: true } 值,并渲染既有的确认文本。拒绝仍是携带评审反馈的失败调用,放弃审阅则是一次指明用户接手的失败调用。
Token 影响
稳定 schema 的成本取决于 ToolRegistry mode,每次传入的 plan 参数和评审结果都会保留在对话历史中。
KV Cache 影响
mode 转换不改变工具目录;plan 参数与评审结果按常规方式扩展对话。
已知限制与暂缓事项
- Plan mode 只进行引导,而不强制执行;需要硬边界的部署必须组合独立的沙箱与批准控制。
- 如果进程在下一个边界之前退出,空闲时作出的待生效选择会丢失,因此 UI 必须重新应用它。
- Fork 的 agent 会继承已记录的 plan 状态,新 spawn 的 agent 则从未激活状态开始;不存在创建时 plan 选项。
- 由另一个 agent 所有的存活子级无法打开
exit_plan_mode审阅。该调用失败时会提示子级在最终结果中包含尚未解决的决策;仅有持久化 fork 谱系并不会阻止恢复为运行时根的会话打开该审阅。 - 只有 Web UI 具备专用的
plan-review渲染器;其他交互提供方可以通过通用选项流程呈现同一请求。
