只想要“照着做一遍”的封装版本(含安装、配置与排错表),见同名技能包 agent-cross-preset-delegation;本仓库是代码本体。
让 AI 自己开一个独立会话去干活,并且可以把结果收回来。
原生 subagent / subagent_fork |
dsh-delegate | |
|---|---|---|
| 换模式(agentPreset) | 不行,继承当前模式 | 可以,十个预设任选 |
| 选渠道模型 | 可以 | 可以,任意已注册渠道 |
| 结果回传 | 自动回、有通知、可续追问 | 等它跑完取回,也可续聊 |
| 上下文 | 干净隔离 | 完全独立的新会话 |
一句话:原生子代理换不了模式,它能。
用同一个模式分别跑原生子代理和一个 delegate 新会话,让它俩各自清点自己收到了什么,结论是:
| 项 | 原生子代理 | delegate 新会话 |
|---|---|---|
| 系统提示章节 | 同一套 | 同一套 |
| 长期记忆 / 用户档案 / 项目关键记忆 | 都有 | 都有 |
| 技能目录 | 有 | 有 |
| 工具集 | 同一批 | 同一批 |
| 会话 ID | 各自的 | 各自的 |
| 工作目录 | 继承父会话 | 跟随调用方会话 |
所以"新对话"并不比原生子代理更干净或更脏——系统提示、记忆、工具是同一份。真正改变上下文的是换模式:换了模式才换掉整套提示、工具和技能目录。
剩下的实际差别只有三点:
- 对话历史——原生
subagent看不到当前对话,subagent_fork能看到已完成轮次,delegate 两者都看不到。 - 可见性——delegate 出来的会话在界面上独立可见,用户能点进去接着聊;原生子代理是挂在本会话下的隐藏子会话。
- 回传方式——原生把结果直接放进当前上下文;delegate 由工具读回来打印。
cd dsh-delegate
node delegate.mjs presets # 有哪些模式可选
node delegate.mjs providers # 有哪些渠道
node delegate.mjs where # 新会话会落在哪个工作目录
node delegate.mjs run --task "任务书" --preset code --timeout 900
node delegate.mjs sessions --limit 10 # 看派出去的会话
node delegate.mjs read <sessionId> # 取结果
node delegate.mjs send <sessionId> --task "再补充..." # 续聊带渠道模型:
node delegate.mjs run --task "..." --preset academic `
--provider siliconflow --model "moonshotai/Kimi-K2.7-Code" --effort high长任务后台派、稍后取:
node delegate.mjs run --task "..." --preset ops --no-wait --title "运维巡检"| 参数 | 说明 |
|---|---|
--task |
必填。新会话看不到当前对话,任务书必须自包含 |
--preset |
academic / code / draw / dsh-codex / mail / mcp / mcu / null / ops / shopping |
--provider --model |
必须成对给。模型 id 见 <DSH_HOME>\settings.yaml 的 llm-pi-ai.providers |
--effort |
high / max / low;硅基的 Kimi 系不支持,传了会报错 |
--cwd |
不给就跟随调用方会话的工作目录(读 DSH_SESSION_ID 反查) |
--title |
新会话的显示标题,便于在界面里认出来 |
--timeout |
等待上限(秒),默认 900。超时不杀任务,之后可 read 取 |
--no-wait |
只派活,立即返回 sessionId |
--json |
结构化输出 |
DSH 的 /api 由两层把关:先查「请求来路是否可信」,再查「浏览器会话签名 cookie」。
本机其他进程直接调用会拿到 401,所以以前那套直接 POST /api/session.create 的脚本在 DSH 升级后全部失效了。
delegate.mjs 的做法是:读取 DSH 自己存在
%DSH_HOME%\.credentials.yaml → records.'client-connection/browser-session'.payload.secret
里的会话签名密钥,按 DSH 的算法(v1.<base64url(payload)>.<HMAC-SHA256 签名>)离线生成合法 cookie 再调用接口。
全程在本机完成,不联网、不外发、不修改 DSH 的任何文件。
该密钥随每次
dsh web重启轮换,工具每次运行自动重取,无需人工处理。
- 接口返回的
turnOutline.response是摘要,长回复会被截断成一句带省略号的预览。取完整回复必须走session/page读事件流,从assistant/message的content里挑type: 'text'的段(同一轮取最后一条非空的)。 session/page需要throughSeq,取自session/list里该会话的projections.asOfSeq。- RPC endpoint 是
namespace/method斜杠格式(session/create),不是点号;body 是{type:'client-request', rpcId, method, payload:{args:{...}}}。 - 参数名因方法而异(
request/_request/ 无参),工具按错误提示自动适配。 - Windows 上不要用
process.exit()收尾——会触发 libuv 断言并打印噪音;只设process.exitCode让进程自然退出。
| 现象 | 处理 |
|---|---|
401 |
dsh web 没在跑,或刚重启;确认端口 3080 后重试 |
404 |
DSH 升级后接口改名。到 node_modules\@deepseek-ai\dsh\node_modules\@deepseek-ai\*\lib\typert.host.js 里核对 namespace / method |
args fields do not match |
该方法参数名不是 request。工具已自动适配三种形态,若仍报错按提示里的 missing "X" 补 |
| 一直不返回 | 那轮还没跑完,用 read <sessionId> 看进度 |
- 派出去的会话会真实留在会话列表里,目前 DSH 没有删除会话的接口——清理要手动在界面里做,别拿它做试验性乱派。
- 相关技能:
dsh-cross-mode-delegation(告诉 AI 什么情况下该用它)。
node test.mjs # 语法检查 + 帮助入口冒烟 + 文档与实现一致性(不需要 DSH 在运行)CI 跑的就是这一条命令,任何 Node ≥18 的机器上都能跑通。
涉及真实派活的命令(run / send / read / sessions / presets / providers)需要 DSH 正在运行,
因此不放进 CI——它们会真的开新会话,而 DSH 目前没有删除会话的接口。
MIT。