DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

viyiviyi /

viyiviyi/dsh-tree-task-flow

Verified

树形任务流 · DeepSeek Harness 插件:把多步任务组织成目标→任务→子任务三级树,节点完成时由 AI 提交结果,插件随即把该节点的执行过程从上下文里折叠掉。

★ 3 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@7aa5fd55

dsh-tree-task-flow · 树形任务流

给 DeepSeek Harness 的上下文管理插件:把用户在这个会话里提的要求记成需求, 需求下面挂任务与步骤;完成[步骤/任务/需求]并折叠过程——模型提交结果, 插件随即把这段执行过程从上下文里折叠掉,只留下那条结果。

这不是项目管理。 需求记录的是"用户在这个会话里要什么",不是"项目长什么样"—— 一条需求可以对应毫无关联的目录,需求列表也不跨会话。模型定义见 docs/09-需求与任务模型.md。

安装即启用:dsh plugin add 之后就生效,不需要再改任何配置。 不想用的时候,在 profile 里写一句 enabled: false 就能关掉,关掉后一个字节都不碰会话。

它解决什么

长任务跑到后半程,上下文里绝大多数内容是过程:读过哪些文件、试过哪些错、 执行过哪些命令。这些内容对后面没有用,但会一直占着位置——每多一轮, 喂给模型的上下文就更长一分,而其中真正需要留住的只有寥寥几句。

真正需要留给后面的只有一句话:这一步做完了,它产出了什么。

所以这里的分工是:

内容 去向
过程 读文件、试错、命令输出、以及已经写进需求的用户输入 节点完成时整段折叠掉
结果 模型在 tree_task_done 里提交的 result 留下来,供后续节点引用
笔记 跟工作有关、但不属于任何一条需求的事实与偏好 跟会话走,不随折叠通告带出;要查用 tree_task_note

折叠按什么切

规则只看表层,与计划树无关(计划树只用来认出"这次完成的是不是一条需求"):

tree_task_start   →  不折叠,只记录开工位置
tree_task_done    →  收「上一个 done 或 start 之后」到这次调用之前(尚未 start 时退到 create)
done 完成的是需求  →  收「这条需求开工那次 create 之后」到这次调用之前(全部)

边界只有三个工具名:create / start / done,按名字认、不看实参。 tree_task_plan 不是边界——它的调用与返回跟普通过程一样,随这一段一起收走。 触发折叠的只有 done;触发这一次的 done 的调用与返回跟着留着。 折叠只收它们之间的过程,换成一条计数通告:

[tree_task_create 调用] [返回:草稿编号]
[tree_task_start 调用]  [返回:R1 需求开始,需求详情:…]
[tree_task消息:此处隐藏了 4 条过程上下文。]
[tree_task_done 调用]   [返回:t-4 任务已完成,结果:… / 后续:…]

为什么 start 不折:开工那一刻还没有值得收的过程;把 start 当折叠点,会把"记录开工" 变成一次上下文重写。done 收的就是前面这一小节——上一个 done 或 start 已经把范围划清了。 start 之前那段不会丢:需求完成时从开工那次 create 起整条收起,start 之前遗留的过程 和中间的任务级通告一起收走;被挡下的过程也等那时一并收。

tree_task_create / tree_task_start / tree_task_done 不能合并成一个工具。 边界是"上一次调用之后"这种位置判定,而 plan 每补一次步骤就调一次;并成一个工具之后, 每次补步骤都会把边界往后推,中间那段过程就永远收不走。靠"实参里有没有 parentId" 去区分,也只是把认错边界的机会交给模型——写漏一个字段,边界就悄悄挪走,还不报错。

两条硬约束:

  • 折叠区间里夹着你的消息就不折——往前折丢了需求,往后折丢了回应, 这一段整段跳过,一个节点都不动;
  • 区间为空(起点那次调用与 done 紧挨着,中间没有过程)也什么都不注入, 不追加、不留空消息。

每一次 tree_task_done 的调用与它的返回都留在上下文里,一轮轮累积; 模型下一轮还看得到"我刚做完了什么、接下来干什么"。tree_task_start 的调用与返回 也留着——它的返回就是需求详情,是"这条需求要做什么"的最近一份摘要。

折叠发生在 agent/pre-step——上一轮已结束、下一个请求还没构造的那一刻。 工具执行中途不能折叠,那时 surface 还在增长,替换会把自己卷进去。

注入消息与 tree_task_done 的返回

一次折叠在上下文里留下两样东西:

一、折叠通告——哪一段被收走了

tree_task消息:此处隐藏了12条过程上下文。
其中修改或生成了文件:
C:\apps\x\c.js

只报条数与修改或生成了哪些文件:过程收走了,但"这活改过哪些文件"得留下, 否则模型要从头再找一遍。只列写入;读取过的文件后续通常还要再读一次,列出来只是噪音。 路径取自工具调用的 file_path / path 参数——界面列出文件变更用的是同一个来源; pwsh / bash 里碰过什么文件看不出来,不计入。通告只讲折叠:不带任务、需求、笔记的提示。

二、tree_task_done 的返回——结果与下一步

t-4 任务已完成,结果:
<提交的 result 原文>

后续:接下来需要进行步骤:「步骤三」(s-8)。
  • 完成需求:R1 需求已完成,结果:<总结>,后面接 后续需求:R2「标题」,没有后续就是 请把结果交付给用户。
  • 完成步骤或任务:<id> 步骤/任务已完成,结果:<result>,后面接后续节点或检查点那句话。
  • result 原样回显,不再另加一份摘要。

按情形,后续那一句是三种之一:

情形 后续
同层还有下一个 接下来需要进行步骤/任务:「标题」(id)。
同层到头、上一层还没交 检查点:任务/目标<id> 的步骤/任务已全部结束,请确认<id> 是否完成,如果完成请调用tree_task_done,如果还需继续,可使用 tree_task_plan 新增步骤/任务继续。
整棵树都完了 请汇报最终结果。

折叠时,这次 tree_task_done 的调用连同它的返回原样留在上下文里,被收走的只是它前面那段过程 ——那一段里若夹着 tree_task_plan 调用,它也跟着一起收走。通告落在触发折叠的那次调用之前。

子任务全部结束,不会让父节点自动完成。 那一刻树进入检查点, 也就是上表第二种返回。

检查点只是提示,不是闸门。 它出现在树上,也出现在 tree_task_done 的返回里, 但插件不会拦住任何工具——"这一层到底做完了没有"由模型判断,插件既不替它定死, 也不靠拒绝别的工具把它逼到墙角。

十个工具

边界必须各有专门的名字,不是可以合并的重复。 tree_task_create / tree_task_start / tree_task_done 是任务流的三个位置标记:create 是"记下这件事"(本身不折叠任何东西), start 是"开工"(只记录位置,不折叠),done 是"收工"(折叠就发生在这里,需求完成时整条收)。 它们各自只在特定时刻调一次,plan 却在任务中途反复调用——并成一个工具, 折叠边界就只能靠实参去猜了(见上一节)。

工具 用途
tree_task_status 开工第一步先调它:需求列表不常驻上下文。不填参数返回 YAML 列表(active / archived / drafts),并展开当前那一条;填 ids 一次查多条全貌;include 选简介 / 版本历史 / 任务结果;match 按关键词找
tree_task_create 把用户提出的一件事记成需求草稿(标题 ≤50 字、简介 ≤200 字、详情不限长)。草稿不算真需求,不进活跃列表;草稿阶段用 tree_task_requirement 的 update 逐次补充正文,确认时用 confirm 生成版本
tree_task_requirement 需求的写操作:confirm 确认草稿并生成版本(第一次 v1,之后每次 +1,title 可不传)/ update 部分更新正文,只改给出的字段,更新后需求回到草稿,可多次调用 / confirmChange 确认用户提交的暂定版本 / question 有歧义退回 / archive、unarchive(可批量,给 ids)/ prerequisites 设前置(id 被设置者,ids 前置编号,整体替换)
tree_task_start 开工:记录开工位置,返回 R1 需求开始,需求详情: 加这条需求的 YAML 详情;本身不折叠,start 之前的过程留到需求完成时收起。草稿要先确认;已完成的不能再开工。调用前先读完所需的文件与文档
tree_task_plan 给一个节点追加子节点:给需求加任务,给任务加步骤。建新需求不归它管;读资料不算任务——那是开工前就该掌握的信息
tree_task_done 完成步骤、任务或需求,并折叠它的过程:每完成一个步骤调用一次,多个节点完成时分别调用。result 必填,缺了直接拒;完成需求时它就是总结。返回 <id> 需求/任务/步骤已完成,结果:<result>,后接后续节点或交付提示。这一次调用连同返回留在上下文里,被收走的是它前面那段执行过程
tree_task_update 改任务或步骤的标题与说明(改需求正文要走 tree_task_requirement,因为要留版本历史)
tree_task_drop 放弃:留个记号说「这件事不做了」,节点留在树里可查(划掉)。放弃需求会连同没做完的任务一起放弃,完成过的保持原样。可批量:给 ids,被父节点带走的子节点自动跳过
tree_task_delete 删除:把它连同下面的东西摘掉、不留痕,不看状态。清理写错 / 建重 / 结果记错的内容用它。可批量:给 ids
tree_task_note 笔记:给 key 与 text 就是写(当场返回,同名覆盖、修订号 +1);要查就只给 query,什么都不给就是全部

放弃与删除是两件事:放弃回答"这件事还要不要做"(历史留着),删除是"这条内容本身就是错的" (凭空摘掉)。一个节点做完之后再想让它消失,只能用删除。

层级固定三级,步骤是最低一级,不能再往下拆。

返回的三条规矩:

  • 写树类工具只返回本次动到的那个需求,不再每次倾倒整份列表;
  • 返回需求或任务列表的工具统一输出 YAML:顶层键说明返回的是什么(requirements / requirement / added_tasks / added_steps),多行正文用块标量,正文一个字不截;
  • 结果全文给出,一个字都不截。
requirements:
  active:
    - id: R1
      status: 进行中
      title: 把菜单改成深色
      intro: 菜单太亮,改成深色
      current: true
      tasks:
        - id: t-1
          status: 已完成
          title: 任务一
        - id: t-2
          status: 未完成
          title: 任务二

三层怎么分

层 是什么 怎么算分对了
需求 用户在这个会话里要什么 标题一句话(≤50 字)、简介一段(≤200 字)、详情不限长;由 AI 与用户沟通后确认
任务 交付节点 一件能独立验收的交付内容——一个文件、一条能跑的命令、一份结论,也可以是一个检查点
步骤 任务内部的一下 一两次工具调用能做完的事

折叠次数跟着 tree_task_done 的次数走:每完成一个任务折一次;完成需求时把它整条收成一条。 所以任务别拆得太碎——够厚,done 的次数少,上下文前缀变动的次数也少。

result 分两层写:任务的 result 写交付物 + 怎么验收(文件在哪、怎么跑、验出什么、 已知限制),步骤的 result 一句话说清这步做了什么就够;需求的 result 就是它的总结, 别的需求靠它快速查阅。

安装

需要 Node.js 22.19 以上,以及能运行 dsh。

从 npm 安装:

dsh plugin --profile web add dsh-tree-task-flow

从源码目录安装(装成 link:,改完源码重启即生效)。把仓库克隆到任意目录, 然后指向那个目录:

dsh plugin --profile web add <插件目录>

dsh plugin add 会把包加进 profile 的 dsh.profile.bundles,而本包自带的 cordis.patch.yml(由 package.json 的 dsh.bundle.patch 指定)会顺势把 task-tree 这一行插进插件列表——装上即启用,不需要再改任何配置。装完可以核对:

dsh --profile web --dump-config          # 输出里应出现 task-tree 这一行,且不带 config

必须重启 dsh web 才生效——运行中的会话不追溯,新工具要在新会话里才会出现。

关闭

不想要了,除了 dsh plugin remove 卸掉,也可以只把它关掉。在 $DSH_HOME/profiles/<名字>/cordis.patch.yml 里写:

- id: task-tree
  config:
    enabled: false

然后重启 dsh web。仓库里的 config.example.yml 有可以直接抄的完整版本。

⚠️ profile 这一层按行覆盖时 config 是整体替换,不是逐字段深合并—— 覆盖时要把想保留的字段一起写全,没写的会走插件默认值(见下面的配置表)。

关掉之后插件一个字节都不碰会话:不注册工具、不加提示词段落、不折叠、不续行、 不挂暂停闸门。只留一条 /task-tree 命令,让你确认它是被关掉的以及怎么打开。

界面

输入框上方的「树形任务流」条目(和内置的待办、目标条目并排,宽度与消息正文对齐)。 外观照内置条目做——用的是同一套 UI 基座(@deepseek-ai/dsh-client-ui-primitives 的图标、Tooltip 与 CSS 变量),所以它看起来就是内置的一部分:

  • 收起时是一条 36px 的单行条:左边清单图标,中间「状态 + 当前需求标题 + 进度」, 右边两个按钮——暂停 / 继续与展开。状态三种:进行中 / 已暂停 / 待开始; 没有进行中的需求时照最近的那一条显(标题与它自己的状态,多半是「已完成」), 不拿「待开始」去描述一条已经做完的需求。
  • 展开后是需求面板,分三段:
    • 活跃需求:一行一条(状态、编号、标题、简介、进度),当前进行中的那条打「当前」;
    • 待确认:还没跟 AI 沟通确认的草稿,不占上下文;
    • 已归档:用户归档掉的需求,同样一行一条,可随时取消归档;
    • 每行三个动作:开始(叫醒 AI 去做这条)、归档 / 取消归档、展开看详情。
  • 点开一条看只读详情:简介、详情全文、缺哪个前置、待确认变动、任务与步骤、总结。 点「改需求」进编辑态:标题、简介、详情三个输入框 + 「确认变更」。 提交之后只是暂定版本,AI 确认之前仍按旧版本走。
  • 归档有一个刻意的延迟:点了之后这一行不动,按钮变成「取消归档」,反悔点一下就回去了; 下次打开面板才按新状态重新分列表。防误点优先于即时一致。
  • 数据每 4 秒自动拉一次,模型在后台改需求时界面会自己跟上。

一条需求都没有的会话一个像素都不占——面板直接返回 null,不会平白挤掉内置的 待办与目标条目。

命令

/task-tree 不经过模型,直接执行:

命令 作用
/task-tree 查看本会话的需求列表与当前进度
/task-tree done <id> <结果> 提交某个节点(需求 / 任务 / 步骤)的结果并完成它
/task-tree drop <id> 放弃:留着可查,标记为不做了
/task-tree delete <id> 删除:连下面的一起摘掉,不看状态
/task-tree pause 暂停:正在跑的工具跑完就停住,不再往下推进
/task-tree resume 继续:从停住的地方接着跑,不往会话里插消息
/task-tree reset 清掉本会话的计划(需求、任务全没)

开关不在界面上,在 profile 的 cordis.patch.yml 里(见上面的「关闭」一节)。

配置

默认值全在 lib/index.js 的 DEFAULT_CONFIG 里:

字段 默认 说明
enabled true 总开关;装上即启用,写 false 关掉
autoContinue false 模型停下时是否自动续行(见下节;在插件管理里本插件那一页能改)
maxAutoRounds 5 连续自动续行的轮次上限
interruptRecovery true 意外中断后是否自动拉起(见下节;在插件管理里本插件那一页能改)
interruptDelaysMs null 网络类中断的拉起时刻,null = 1/5/10/30 分钟
promptOrder 1800 工具说明段落的排序
rootDir null 状态目录,默认 $DSH_HOME/dsh-task-tree

设置

设置在插件管理里、这个插件自己的那一页:打开侧边栏的「插件」页,在「已安装」里点 dsh-tree-task-flow 这张卡,页面上描述下面就是这两个开关。改完立刻生效,不用重启。

它不在 DSH 的设置面板里,也不在任务条上。设置属于这个插件,就该长在插件自己身上; 任务条只干两件事:看进度、按暂停 / 继续。

设置 默认 做什么
自动续行 关 模型自己停下、计划树还没跑完时,要不要推一条"接下来做 X"把它唤醒
工具出错自动拉起 开 这一轮不是正常结束(网络断了 / 模型输出坏了 / 工具结果没了)时,要不要自动重来

两项是两件事,别混:前者是"要不要往前推",后者是"要不要救"。默认这么定是因为 自动续行会在你没看着的时候自己往下跑,该由人来点;而中断拉起只在"这一轮根本不是正常 结束"时动手,正常停下它一步都不动。

设置写在状态目录的 settings.json 里(不按会话分,整个插件一份),重启后还在。 优先级是 在插件页里改过的 > profile 里的 config > DEFAULT_CONFIG:在页里点过就以 页为准,免得界面对不上 YAML。enabled、maxAutoRounds、interruptDelaysMs 这类 "装插件时就该定好"的项不在开关名单里,仍然只认 profile 配置。

意外中断自动拉起

上一节 autoContinue 管的是"模型自己正常停下"。这一节管的是这一轮没能正常 结束:网络断了、模型 API 报错、或者工具执行到一半进程没了。这两种停法插件原先不管, 会话就一直躺在那里。

判据全部取自 DSH 自己写下的数据,不看文本:

中断 怎么认 什么时候拉起
网络 / API turn/end 的原因是 error,错误码是 TRANSPORT、TIMEOUT、SERVER、RATE_LIMIT、EMPTY_RESPONSE 中断后 1 分钟、5 分钟、10 分钟、30 分钟各一次
模型输出损坏 turn/end 的原因是 error,错误码是 MALFORMED_RESPONSE(模型给出的工具入参不是合法 JSON) 立即一次
工具执行 这一轮出现过 TOOL_OUTCOME_UNKNOWN / TOOL_NOT_STARTED 的合成工具结果(意思是"这次调用没留下结果") 立即一次

后两类虽然都"立即一次",处置并不一样——差别在于有没有东西要勘察、有没有东西可收:

  • 工具执行类:那次调用确实发生过,只是结果没落盘。拉起消息会明确说"它到底做没做 没人知道,先确认那一步的实际影响再决定要不要重做";第二次仍然失败时,把那条拉起消息、 发起该调用的助手消息、以及它的合成错误结果一起收走(和折叠同一套机制,界面上仍可 展开),再拉一次。
  • 模型输出损坏类:DSH 是在解析响应流时就判了死刑——整条响应被作废,一个工具都没 执行,连 tool/call 都没落盘,没有任何副作用要勘察。拉起消息只说"原样重做那一步, 把引号括号写全,必要时一次只调一个工具";第二次仍然失败时什么都不收(没东西可收), 直接再拉一次。

两类都是第三次同类中断就停手,链上记 exhausted。

几条边界:

  • 余额不足(QUOTA)不拉。 等再久也不会自己好。
  • 你按下的停止,永远不拉。 和自动续行的第 1 条闸门一致。
  • 普通工具报错不拉。 比如"文件没找到""edit 没匹配上""网址被拦"——这些模型看到就能 自己改道,本来也没中断这一轮。
  • 只在这个会话的计划树还没走完时才动手。等待时刻写在状态目录的 revive/ 下, 重启 dsh web 不会丢。
  • 能在插件页里关掉。 插件管理里本插件那一页的"工具出错自动拉起"就是 这个开关,改完立刻生效(关掉之后插件连 revive/ 都不再写)。

暂停与继续

界面上的暂停按钮(或 /task-tree pause)是真暂停,不是"关掉自动续行":

  • 正在执行的那个工具会正常跑完,不会被中途掐断;
  • 它跑完之后,会话就静静停在原地——不再发起模型请求,也不再往下走一步;
  • 全程不往会话里插任何消息,上下文干干净净。

继续(界面按钮或 /task-tree resume)就是从这个岔口放行:模型从它原本要请求的地方 接着请求,同样零新增消息。任务树的进度停在哪儿,就从哪儿接着跑。

重启 dsh web 之后暂停依然有效。 "被按住"这件事写在状态目录的 held/ 下, 重启后条目仍显示「已暂停」,点「继续」即可接着跑。

点「继续」是无条件的。 不管此刻闸门有没有挂在岔口上、会话是不是正忙,点一下, "被按住"就当场解除——它是一句"接着跑",不是一次"此刻有没有闸门"的查询。区别只在 插件接下来能做什么:

  • 闸门正挂在岔口上 → 直接放行那一步,零新增消息;
  • 没有岔口可放(进程重启过,或者你点的时候那个工具还在跑)→ 退一步给会话排一条 「恢复续行」的消息把它从 idle 推起来;会话正忙的话连推都不用推,它自己会在下一个 岔口接着跑;
  • 那个会话还没被 DSH 加载成实时 agent → 提示你先打开它或在其中发一条消息, 但"被按住"照样解除。

早先不是这样:"继续"只在闸门恰好挂着的那一瞬间才算数;没有闸门可放时又要求会话 正好停在 idle,忙就直接拒绝、并且什么都不清。于是"工具还在跑的时候点的那一下" 被静默吞掉,等闸门真挂上时已经没人在等它——会话就停在原地了。真回归见 verify-pause.mjs 的场景 s-31。

闸门开在 agent 的 agent/pre-step 上——一个 step 走完、工具结果都已落盘、模型还没 发起下一次请求的那一刻。这是唯一同时满足"不打断工具"和"不留痕迹"的位置:再晚一点 的 agent/turn-stopping 一旦放行,就得靠 steer() 推一条消息才能续上,那就留下痕迹了。

闸门只拦自动推进,不拦真人发言。 暂停期间你自己发一条消息,说明你要它跑, 插件会直接放行并解除暂停,不会把你堵在门外。

暂停期间人按界面上的停止(中断本轮)也不会卡住:闸门盯着本轮的取消信号, 信号一 abort 就立刻放行。

自动续行

模型自己停下、计划树却没跑完,插件就推一条"接下来要做 X"把它唤醒。 这只是兜底: tree_task_done 的返回文本里已经带了"请继续执行下一个子任务",模型通常会在同一轮里接着做。

autoContinue 默认关闭——它会自己往下跑,所以默认由人来点。要开就在插件管理里 本插件那一页打开(改完立刻生效,不用重启),或者在 profile 里写 autoContinue: true。

开着也不会脱缰,有四道闸门:

  1. 中断即停——你按下停止,落盘的 turn/end 会记成 reason.kind = "aborted", 插件从那里认,把这个会话标记为不再自动续行(落盘在 held/ 下,跨重启有效), 直到真人再发一条消息。

    这里不能用 agent/turn-stopping 的 signal.aborted 当判据。 那个事件只在 "这一轮本来就要正常收尾"时才发(dsh-agent-loop 里唯一一处 dispatch 前面刚做过 throwIfAborted());你按停止会让信号 abort、从别处抛出,catch 里直接记下 turn/end 就重新抛出,那条 dispatch 走不到——signal.aborted 在那里几乎永远是 false,拿它当闸门等于没闸门。

  2. 轮次上限——连续续行达到 maxAutoRounds(默认 5)就停;只有真人发的消息才重置配额。
  3. 不抢排队输入——队列里还有你排着的话时,让用户先说。
  4. 暂停压住它——/task-tree pause 之后,即使模型自己停了下来,兜底也不会把它拉起来; /task-tree resume 再放开。

agent/status 只在状态变化时发。 重启 dsh web 之后,一个本来就停在 idle 上的 会话不会产生这个事件(新建的 agent 一开始就是 idle),所以它不会被自动唤醒—— 要它动,你得在那个会话里先说一句话。从下一次模型自己停下开始,续行就接手了。

状态文件

全部在 $DSH_HOME/dsh-task-tree/ 下。除 settings.json 外都以 sessionId 为键:

文件 内容
plans/<sessionId>.json 需求与任务(每个会话一份,需求住在里面的 goals 键上——历史键名)
notes/<sessionId>.json 笔记(跟会话走,不跨会话带)
surfaces/<sessionId>.json 三层的进度游标 { key, cursor }(只给界面看,不参与折叠)
held/<sessionId>.json 暂停 / 停止状态(跨重启保留)
revive/<sessionId>.json 意外中断的拉起时刻表(跨重启保留)
settings.json 在插件页里改过的设置(整个插件一份,不按会话分)

目录名沿用插件改名前的标识,为的是不让既有的计划文件失联;插件名与它无关。

旧版的文件里没有需求那一层的字段(versions / archived / prerequisites 等)。 读的时候在内存里补齐,不改写磁盘上的老文件——老会话照常能读。

计划属于建立它的那个会话。放到会话无关的位置,任何一个会话的计划都会被 所有会话读到——那等于把不相干的节点指派塞进别人的上下文。

写入一律走「临时文件 + rename」,进程崩在写入中途也不会留下半截 JSON。 插件绝不直接写会话日志,会话里的一切都走 session.append()。

你会观察到的行为

  1. 完成必须写 result。 节点的执行过程会被折叠掉,result 是它唯一的出口; 空 result 会被拒绝。所以要写清"产出了什么",写成能独立看懂的样子—— 过程会丢,别把过程写进去。

  2. 每完成一个步骤就报一次完成,不要合并。 折叠只发生在完成的那一刻:四个任务全部做完 再连续补四次 done,中间那两百多条过程会一直留在上下文里。实测过一轮对照——合并补报 的会话,每步平均输入 174.7k token,不用插件的对照组是 167.0k,插件反而更贵。 这条插件无法代替模型决定,所以写进了系统提示词与工具说明里。

  3. 折叠只看表层。 done 从上一个 done 或 start 之后折(尚未 start 时退到 create), 完成需求时从开工那次 create 折整条;start 只记录位置、不折叠。tree_task_plan 不是边界, 它的调用与返回跟过程一样会被收走。区间里没有过程时什么都不注入,夹着你的消息时 整段不折——那一段原样留着(往前折丢需求、往后折丢回应),等这条需求完成时连同其他过程一起收走。

  4. 模型看到的工具说明不随计划变化,也不复述工具清单。 那一段只讲什么时候用 这组工具、完成时守什么规矩;每个工具的用法由它自己的 description 承担。 要了解计划就让模型调 tree_task_status。

  5. 折叠几次,界面就多几张「系统提示词」卡片,但上下文里的系统提示词始终只有一条。 DSH 把"上下文被替换过"记成一次请求序列的边界(下一次请求带 reason=series), 界面在 reason 不是 change 的请求上都会画一张系统提示词卡片;锚点跟着那一轮 step 走, 卡片于是一张张堆起来。上下文里 system/message 自始至终只有一条,折叠没有伪造 任何系统消息。已实测:3 次折叠 → 3 次 series → 界面 3 张卡片。

  6. 改需求用「丢弃 + 追加」,不要重建整棵树。 丢掉的节点留在树里可查, 它和完成的节点会一起被那一段折叠收走(通告只报条数,不区分完成还是丢弃)。 内容写错了才用删除——删除是摘掉,摘掉的东西查不回来,也没有任何通告替它留痕。

  7. 暂停不留痕迹。 暂停后模型看到的是"没有下一条请求",看不到任何"你被暂停了" 之类的提示;继续之后也不会有"继续"消息进上下文。想让模型知道中间发生过什么, 得自己发消息说。

  8. 内置压缩之后会有一条提醒。 DSH 自己的压缩把一大段历史收成一条检查点之后, 如果这个会话里有计划树,插件会注入一条 tree_task消息:上下文刚被压缩过,计划树没有被压缩。用 tree_task_status 取回当前进度…。 计划树本身不在压缩范围内——它存在磁盘上;但模型会忘掉它,所以补这一句。 同一个压缩点只提醒一次,之后再被压缩会再提醒一次。

不做的事

不做 原因
资料 / 文件快照 / 记忆 上下文里值得留下的只有结果,其余靠模型自己重读
文件回退 / 撤销 改需求用「丢弃 + 追加」;内容本身写错了才用删除摘掉,摘掉就找不回来
并行推进多个目标 结构上支持一个会话有多个目标(目标层就是兄弟列表),但同一时刻只沿一条活动路径走
把计划内容注入提示词 计划状态由 tree_task_status 现取,提示词里只放不随计划变化的说明

卸载

dsh plugin --profile web remove dsh-tree-task-flow

状态目录不会自动清理,需要的话手动删 $DSH_HOME/dsh-task-tree。

许可

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 7aa5fd55a005

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout