npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xmoon76/dsh-subagent-router

v0.3.1

Published

DSH model-facing delegation tool that routes continuable/one-shot subagents to a model-selected LLM provider and model

Readme

@xmoon76/dsh-subagent-router

English | 中文

一个面向模型的 DSH 插件,用于在模型选定的 LLM provider 与 model 上启动子 agent(subagent)。模型选择路由(provider/model);部署方拥有子 agent 后端(subagentProvider,默认 spawn)、默认调度策略(backgroundMode)与路由白名单(allowedProviders)。单次调度的调度方式可用可选参数 run_in_background 覆盖,与官方 @deepseek-ai/dsh-tool-subagent 工具完全一致。continuable 子 agent 的后续轮次复用 @deepseek-ai/dsh-tool-subagent-control 的官方 send_message / list_agents / interrupt_agent 工具;后台 one-shot 任务用 @deepseek-ai/dsh-tool-jobs 的官方 job_output / job_kill 工具收集。

安装(以 DSH profile bundle 方式)

本包以 DSH profile bundle 形式发布:其 cordis.patch.yml(dsh.bundle.patch)会在 profile 组合中自动插入两个 router 行——tool-subagent-router(spawn + continuable,subagent_route)与 tool-subagent-router-fork(fork + one-shot,subagent_fork_route)。前提是 profile 的 bundles 包含 @deepseek-ai/dsh-base(所有官方 web/headless 模板都满足)——subagents 注册表及其 spawn/fork 后端来自该 base 层。

dsh plugin --profile <name> add @xmoon76/dsh-subagent-router

该命令把包安装进 profile,并把它加入 profile 的 dsh.profile.bundles 层列表;下次启动时其 patch 按下方默认配置插入两个 router 行(tool-subagent-router 与 tool-subagent-router-fork)。若要覆盖默认值,在 profile 自己的 cordis.patch.yml 里 patch 对应行 id(patch 会替换该行整个 config):

- id: tool-subagent-router
  config:
    allowedProviders:
      - deepseek-official

使用指南(Usage walkthrough)

下面是一个面向模型的实际调用流程。派发前请确认 profile 已注册 router 工具(subagent_route / subagent_fork_route),且所选 provider/model 路由已经配置。

启动可继续的子 agent(默认后台)

subagent_route 的 description / prompt / provider / model 全部必填。模型只选择 LLM 路由;部署配置仍拥有后端与默认调度策略:

{
  "description": "say hi",
  "prompt": "请简短地打个招呼,然后说明你正在使用哪个模型。",
  "provider": "codex",
  "model": "gpt-5.6-luna"
}
// continuable 结果:started subagent <id>

continuable 结果只确认 inbox 已接受请求并返回持久 id,不包含子 agent 回复。请等待 DSH settlement notice,或按 id 查看子 agent transcript。

同步等待全新子 agent

当下一步必须依赖子 agent 结果时,设置 run_in_background: false。该调用会以前台方式运行子 agent 并直接返回其最终输出,而不是返回 id:

{
  "description": "review implementation",
  "prompt": "Review the diff and report concrete risks.",
  "provider": "codex",
  "model": "gpt-5.6-luna",
  "run_in_background": false
}
// foreground 结果:子 agent 的最终输出

多轮继续对话

子 agent 被接受后,使用官方 send_message 控制工具排队下一轮 FIFO 消息:

{
  "subagent_id": "<id>",
  "message": "你最擅长哪些工程任务?"
}
// message queued as the next turn for subagent <id>

后续轮次及 cold resume 都保持创建时的 provider/model;不支持会话中途切换路由。

配套控制工具

以下控制工具不属于本包:继续控制必须从官方 @deepseek-ai/dsh-tool-subagent-control 插件单独挂载,后台任务控制来自官方 @deepseek-ai/dsh-tool-jobs 插件:

| 工具 | 用途 | |---|---| | send_message | 向持久子 agent 排队下一轮(FIFO)。 | | list_agents | 列出或回忆已启动的子 agent。 | | interrupt_agent | 中断正在运行的子 agent 轮次。 | | job_output | 收集后台 one-shot 任务的输出。 | | job_kill | 停止后台 one-shot 任务。 |

官方委托工具(subagent、subagent_fork)是另一回事:它们是 @deepseek-ai/dsh-tool-subagent 的不同实例,绑定固定的部署路由。本 router 从不替换它们——参见下方官方工具共存。

启动动态 fork(one-shot)

subagent_fork_route 由 bundle 默认挂载(fork + one-shot),因此继承父会话已完成轮次的 fork 子 agent 开箱即用。实例使用不冲突的名字(绝不用官方 subagent_fork):

# bundle 插入的默认值(可在 profile 里按 row id 覆盖)
- id: tool-subagent-router-fork
  config:
    subagentProvider: fork
    toolName: subagent_fork_route
    backgroundMode: one-shot
    enableRunInBackground: true
    maxDepth: 3

模型调用(默认等待结果):

{
  "description": "review prior design",
  "prompt": "Review the design discussed above and identify correctness or maintainability risks.",
  "provider": "openai",
  "model": "gpt-5.6"
}
// foreground 结果:子 agent 的最终输出

Fork prompt 语义:子 agent 已经看到父会话的已完成轮次,prompt 只需写新增任务;当前 in-flight 父轮次不在 fork seed 中。

后台运行 fork

设置 run_in_background: true 注册一个后台 Task 并立即返回其 job id:

{
  "description": "deep review",
  "prompt": "Perform a deep review of the design.",
  "provider": "codex",
  "model": "gpt-5.6-luna",
  "run_in_background": true
}
// background 结果:started background subagent job <id>

用 job_output 收集结果,用 job_kill 停止工作。后台 fork 是一次性 Task,不是 continuable 子 agent:不能用 send_message 继续它。

最佳实践

  • 全新(spawn)子 agent 的 prompt 要自包含:它看不到父会话。
  • fork(fork)子 agent 的 prompt 只需写增量:子 agent 继承父会话已完成轮次,只写新任务即可;当前 in-flight 轮次不在 fork seed 中。
  • 派发前确认 provider/model 可用。没有模型发现工具,路由错误可能直到子 agent 首次解析路由时才出现。
  • 把 continuable 启动结果当作确认而非子 agent 答案;实际结果通过 settlement notice 和 transcript 获取。
  • 独立委派优先使用后台默认:在同一个 assistant turn 里一起启动多个子 agent,并在它们运行期间继续做其他有用工作;只有下一步依赖结果时才用 run_in_background: false。
  • 如果部署策略需要限制路由,用 allowedProviders 配置;不要依赖 prompt 文案强制执行。
  • 不要把凭证、endpoint、headers 放进 prompt 或工具参数;多实例挂载时为每个实例使用唯一的 toolName。
  • 记住 maxTokens 不会在 activation 之间持久化。

为什么需要这个包

官方 @deepseek-ai/dsh-tool-subagent 把一个实例绑定到一个固定的子 agent agentOptions(部署固定 provider/model)。本插件把 LLM 路由选择交给模型,同时让所有能力仍由 DSH seam 拥有:它只是 ctx.subagents.startContinuable() / ctx.subagents.start() 与 ctx.jobs 之上的薄 Consumer,不重新实现 continuation、session、持久化、权限、任务或队列。调度与生命周期语义其余部分与官方工具一致。

契约(Contract)

面向模型的工具 subagent_route / subagent_fork_route 接受相同的参数:

| 参数 | 必填 | 含义 | |---|---|---| | description | 是 | 委托任务的简短(3-5 词)标签。 | | prompt | 是 | 完整独立任务(全新子 agent)或基于已完成轮次的增量(fork 子 agent)。 | | provider | 是 | 子 agent 使用的已配置 DSH LLM provider 路由。 | | model | 是 | 子 agent 对话使用的 model id。 | | run_in_background | 否 | 调度覆盖。continuable 实例默认 true(返回持久 id);one-shot 实例默认 false(返回最终输出)。enableRunInBackground: false 时该参数不存在。 |

成功时根据实例的 backgroundMode 与本次调用的 run_in_background 返回三种规范结果之一:

| 类型 | 何时 | 结构 | |---|---|---| | continuable | continuable 模式 + 后台(默认) | { kind: 'continuable', subagentId } —— 持久 id,inbox 接受时解析 | | foreground | 任意模式 + run_in_background: false(或 one-shot 默认) | { kind: 'foreground', runId, output } —— 子 agent 最终输出 | | background | one-shot 模式 + run_in_background: true | { kind: 'background', jobId } —— 用 job_output 收集,job_kill 停止 |

凭证、endpoint、headers、maxTokens、outputSchema 与后端选择绝不暴露给模型。

配置(Config)

| 键 | 默认 | 含义 | |---|---|---| | subagentProvider | spawn | ctx.subagents provider 名。continuable 模式要求 prepareContinuable;one-shot 模式要求可 start 的 provider(fork 是受支持的 one-shot 后端)。 | | backgroundMode | continuable | 默认调度策略:continuable 调用 startContinuable() 并返回持久 subagent id;one-shot 调用 start() 并返回 run 的最终输出。run_in_background 可逐调用覆盖。绝不由模型选择。 | | executionMode | — | 已弃用的 backgroundMode 旧别名。与 backgroundMode 同时配置时必须一致,否则插件启动时 loud 失败。 | | enableRunInBackground | true | 模型侧 run_in_background 参数是否存在并被采纳。false 时从 schema 移除该参数并强制所有调用走前台;伪造的 run_in_background: true 会在 execute() 中被拒绝。 | | toolName | subagent_route | 面向模型的工具名;每个已加载实例必须不同。 | | maxDepth | 3 | 绝对委派深度上限,或 'provider-managed' 表示不设上限。 | | persona | — | 覆盖 deployment:persona 的每子 agent persona。 | | toolFilter | — | 每子 agent 的全局工具限制;要求 toolFilter 能力。 | | allowedProviders | — | 部署侧 LLM provider 白名单,在任何子 agent 工作开始前于 execute() 中强制;显式 [] 拒绝所有。 |

路由策略(Routing policy)

  • 模型只选择 LLM 路由:provider 必须命名已注册的 DSH LLM adapter 路由,model 必须是其上的 model id。
  • allowedProviders 是 executor 级强制,不是提示词暗示。provider/model 的有效性最终由子 agent 首次请求时的 DSH LLM/Agent 解析决定(不做 listModels() 硬白名单,保留动态 model 路由)。
  • 子 agent 后端与默认调度策略是部署配置;模型从不选择它们。

继续对话行为(Continuation behavior)

  • continuable 子 agent 是持久对话:send_message(官方控制工具)投递后续 FIFO 轮次,list_agents 列出它,interrupt_agent 中断它——全部走 ctx.subagents 的权威路径。
  • cold resume 保持相同的 agentProvider/agentModel:持久 descriptor 保存它们,因此恢复后的 Activation 仍使用创建时的路由。
  • provider/model 在创建时固定;不存在会话中途切换模型。
  • 后台 one-shot 任务是 Task,不是 continuable 子 agent:job_output / job_kill(官方 @deepseek-ai/dsh-tool-jobs)是它的控制工具,send_message 不能继续它。

官方工具共存(Official tool coexistence)

本插件不替换官方 subagent / subagent_fork 工具。两者在同一 composition 中同时挂载时:

subagent            -> 官方 fresh child,  固定路由,   continuable
subagent_route      -> router  fresh child,  动态路由, continuable
subagent_fork       -> 官方 继承已完成轮次,  固定路由,   one-shot
subagent_fork_route -> router  继承已完成轮次,  动态路由, one-shot
send_message        -> 官方(@deepseek-ai/dsh-tool-subagent-control)
interrupt_agent     -> 官方(@deepseek-ai/dsh-tool-subagent-control)
list_agents         -> 官方(@deepseek-ai/dsh-tool-subagent-control)
job_output          -> 官方(@deepseek-ai/dsh-tool-jobs)
job_kill            -> 官方(@deepseek-ai/dsh-tool-jobs)
job_list            -> 官方(@deepseek-ai/dsh-tool-jobs)

两个 router 工具与官方对应工具的唯一区别在 child route:官方实例使用部署固定的 provider/model,而 router 让模型在每次调用时选择 provider/model。其余一切——调度、run_in_background 语义、结果类型、system-prompt 引导——完全一致:

| 工具 | Child | 路由 | 生命周期 | |---|---|---|---| | subagent | fresh | 固定 | continuable(send_message) | | subagent_route | fresh | 动态 | continuable(send_message) | | subagent_fork | 继承已完成轮次 | 固定 | one-shot(job_output / job_kill) | | subagent_fork_route | 继承已完成轮次 | 动态 | one-shot(job_output / job_kill) |

router 从不 shadow、替换或修改官方工具定义:它只注册自己的工具名,官方 schema 与行为保持原样(由共存测试套件锁定)。

支持矩阵(Support matrix)

| 后端 | backgroundMode | run_in_background 省略 / false | run_in_background: true | 状态 | |---|---|---|---|---| | spawn | continuable | 前台(等待输出) | 持久 continuable 子 agent | ✅ 推荐 | | fork | one-shot | 前台(等待输出) | 后台 Task(job_output / job_kill) | ✅ 推荐 | | spawn | one-shot | 前台(等待输出) | 后台 Task | ⚪ 兼容 | | fork | continuable | 前台(等待输出) | 持久 continuable 子 agent | ⚠️ 非推荐 |

router 是通用 provider Consumer,因此当 provider 暴露 prepareContinuable() 时并不硬拒绝 fork + continuable——但产品文档推荐 fork + one-shot。

工具名冲突规则(Tool name collision rules)

  • 每个已加载 router 实例需要唯一的 toolName。名字已被工具注册表占用时,mount 会在注册任何东西之前 loud 失败。
  • DSH 官方 subagent/control 名字(subagent、subagent_fork、send_message、interrupt_agent、list_agents)被配置为 router toolName 时给出专用诊断。
  • 永远不要把 router 的 toolName 配成 subagent 或 subagent_fork。随 bundle 提供的是 subagent_route(spawn + continuable)与 subagent_fork_route(fork + one-shot);更多实例须自行选用唯一名字。

模型体验(Model Experience)

工具 schema

模型看到什么

注册的 router schema(subagent_route / subagent_fork_route):description、prompt、provider、model(全部必填)加可选的 run_in_background 覆盖。description/prompt 文案跟随后端 provider 的 inheritsParentContext:全新子 agent 被告知要提供完整独立 prompt;fork 子 agent 被告知它已看到已完成轮次。continuable 实例说明 run_in_background 的 true 默认值、settlement notice 与显式前台覆盖;one-shot 实例说明 false 默认值与用 job_output / job_kill 收集的 job id。不存在 api_key、base_url、max_tokens 或后端/模式参数。

Token 影响

工具可见的每个请求有固定 schema 成本;本包除 continuable 实例的 tool:<toolName> 引导 section(见下)外不贡献 system-prompt section。

KV Cache 影响

注册的工具 schema 不变时前缀稳定;provider 注册生命周期可能在首个变化的工具定义处使复用失效。

System-prompt 引导

enableRunInBackground: true 的 continuable 实例贡献一个 tool:<toolName> system-prompt section(order 116.5),告诉模型默认后台委派、在同一个 assistant turn 里一起启动独立委派、在子 agent 运行期间继续工作,并且只有下一步依赖结果时才用 run_in_background: false。工具缺席(provider 尚未注册或已被移除)时该 section 渲染为空,因此 HMR 不会残留过期引导。one-shot 实例不贡献 section。

工具结果

模型看到什么

started subagent <id>(continuable)、子 agent 的最终文本(foreground)或 started background subagent job <id>(background)。continuable 结果不携带子 agent 回复;子 agent 按 id 的 transcript 是其行为的来源,settlement notice 独立到达。

Token 影响

每次被接受的创建追加一条短结果(continuable)、每次任务注册追加一条(background),或子 agent 输出(foreground)。

KV Cache 影响

在可复用请求前缀之后仅追加。

已知限制与延后工作(Known Limitations and Deferred Work)

  • 不支持会话中途切换模型 —— provider/model 在创建时固定;持久 descriptor 保存它们,因此恢复后的 Activation 仍使用创建时的路由。
  • 没有模型发现工具 —— 模型必须已经知道已配置的 provider/model id;只读发现工具延后。
  • 后台启动的 continuable 子 agent 无法被发起调用的工具同步收集 —— 它的 settlement 通过 continuation notice 机制到达,按 id 的 transcript 仍然可用;下一步依赖结果时请用 run_in_background: false。
  • maxTokens 不可持久化 —— 每次 activation 的预算不保存在 DSH continuable descriptor 中,因此工具不暴露它。
  • 只能使用已配置的 LLM adapter/route —— 子 agent 路由必须在请求时解析;provider/model 有效性可能直到子 agent 路由解析时才失败(按设计不做 listModels() 硬白名单)。
  • 继续控制需要官方 control 工具 —— send_message / list_agents / interrupt_agent 来自 @deepseek-ai/dsh-tool-subagent-control,需单独挂载。
  • 后台 one-shot 任务需要官方 jobs 栈 —— ctx.jobs(@deepseek-ai/dsh-jobs + 一个注册表实现,如 @deepseek-ai/dsh-jobs-local)与 job_output / job_kill 工具(@deepseek-ai/dsh-tool-jobs);没有它们时后台调用 loud 失败。
  • one-shot 输出不流式 —— run 的最终输出在子 agent settle 后一次返回;中间步骤留在子 agent 的 transcript 中。
  • 输出 schema 使用 DSH tools 的 value-schema 方言 —— 规范 foreground output 是 { type: 'array', items: { type: 'json' } },其中 'json' 是 @deepseek-ai/dsh-tools 基于 Schemastery 的 value 类型(官方 tool-subagent 使用的同一方言),不是裸 JSON-Schema 关键字;只有 DSH 的 tool registry 消费它。

开发(Development)

前置条件

Node.js ≥ 22 与 npm。所有 DSH peer 依赖都从 npm registry 解析(@deepseek-ai/dsh-* 0.1.0-rc.x),因此不需要 deepseek-harness checkout。

门禁(Gates)

npm run typecheck   # 对 src + tests 跑 tsc
npm run lint        # oxlint
npm run test        # vitest(包级集成 + Loader composition)
npm run test:coverage  # src/ 每文件 100%
npm run build       # tsc 输出到 lib/
npm pack            # tarball smoke(结构、内容、独立安装)