Bundle
@huanlin/dsh-plugin-yet-another-subagent
Configurable subagent profiles with web UI settings, real-time toolcall/token display, and click-to-navigate child sessions.
- Source
- HuanLinOTO
- stars
- 15 stars
- License
- AGPL-3.0
- Updated
- Updated yesterday
Readme
<p align="center">
<a href="https://dshfind.com/zh/plugins/huanlinoto/dsh-plugin-yet-another-subagent"><img src="https://dshfind.com/api/card/huanlinoto/dsh-plugin-yet-another-subagent?lang=zh" alt="dsh-plugin-yet-another-subagent card"></a>
</p>
# yet-another-subagent
[](https://www.npmjs.com/package/@huanlin/dsh-plugin-yet-another-subagent)
可配置的子代理(subagent)profile 系统,提供单一 `subagent` 工具 + `profile` 参数选择,支持 Web UI 设置、实时进度展示(工具调用/token/活动)、子代理树标签页、点击跳转子会话。
## 架构
单 bundle,双入口(host `.` + client `./client`)。
> 不发布 `./invariant`:本插件的工具/RPC/projection 注册均无独立可分歧的运行时观察(HMR 安全性由测试证明),无内容可校验——按 DSH 0.1.2-rc.1 收紧后的 invariant 规则(禁止空 installer)省略该入口及其全部接线。
- **Host 半**(`src/index.ts`):
- 单一 `subagent` 工具,通过 `profile` 枚举参数选择 profile(非每 profile 一个工具)
- 复用官方 `spawn` provider,支持前台(foreground)和后台(continuable / one-shot)两种模式
- Profile 状态通过 settings seam 持久化到 `$DSH_HOME/settings.yaml`
- RPC CRUD:`ya-subagent.profiles.*` / `.tools.list` / `.sessions.repair`(`/api` 上的 exact Fetch route,经 `connection.fetch.register` 注册)
- 两个 session projection:`subagentProfile`(父会话 childId→profileId 映射 + callId→childId)+ `yaSubagentProgress`(子会话实时 toolcall/token/活动状态);wire view 已做引用记忆化,适配 dsh 0.1.2-alpha.3 起 change feed 的 `Object.is` 下发门控(内容不变即静默)
- **Client 半**(`src/client/index.ts`):
- `settings.section` — Profile 编辑页
- `tool.call.toolview`(key `subagent`)— `SubagentCard` 工具调用卡片
- `conversation.view`(id `subagent-tree`)— `SubagentTreeView` 子代理树标签页
`cordis.patch.yml` 只禁用官方 `tool-subagent`(spawn 路径),保留 `tool-subagent-fork`(无名称冲突)。
## 配置
```yaml
# cordis.patch.yml
- id: tool-subagent
disabled: true
- insert:
- id: yet-another-subagent
name: '@huanlin/dsh-plugin-yet-another-subagent'
config:
profiles:
- id: general
label: General
model: { kind: 'auto' }
persona: { kind: 'inherit' }
toolFilter: { kind: 'none' }
maxDepth: 3
backgroundMode: continuable
builtin: true
generalFixed: true
```
### Profile 字段
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `id` | `string`(小写字母/数字/连字符,1-32 字符) | — | Profile 唯一标识 |
| `label` | `string` | — | 显示名 |
| `model.kind` | `'auto'` \| `'manual'` | — | `auto` 继承父代理模型;`manual` 指定 |
| `model.provider` | `string` | `''` | Provider(仅 `manual` 时使用) |
| `model.model` | `string` | `''` | 模型 ID(仅 `manual` 时使用) |
| `persona.kind` | `'inherit'` \| `'custom'` | `'inherit'` | `inherit` 跟随部署人设;`custom` 自定义 |
| `persona.text` | `string` | `''` | 自定义人设文本(仅 `custom` 时使用) |
| `toolFilter.kind` | `'none'` \| `'allow'` \| `'deny'` | `'none'` | 工具过滤策略 |
| `toolFilter.tools` | `string[]` | `[]` | 过滤工具列表 |
| `maxDepth` | `number` | `3` | 最大递归深度 |
| `backgroundMode` | `'continuable'` \| `'one-shot'` | `'continuable'` | `run_in_background: true` 时的后台策略 |
| `builtin` | `boolean` | `false` | 是否为内置 profile(仅展示用) |
## 开发
```sh
pnpm install # 安装开发依赖 + zod(唯一运行时 npm 依赖)
pnpm run typecheck # tsc --noEmit(通过 ../dsh 解析 DSH 源码)
pnpm test # vitest run
pnpm run build # tsc + tsdown → lib/index.js, lib/client.js
```
### 类型检查
`tsconfig.json` 继承 `../dsh/tsconfig.base.client.json`,通过 `pnpm-workspace.yaml` 的 `packages/*/*` glob 解析 DSH checkout 的源码。需在 `../dsh` 存在 DSH checkout 的同级目录下运行。
## 运行
```sh
# 从 npm 安装(推荐):
dsh plugin --profile web add @huanlin/dsh-plugin-yet-another-subagent
# 本地引用(开发热更新)
dsh plugin --profile web add "link:D:/Projects/deepseek-harness/yet-another-subagent"
```
安装后重启 `dsh web` 进程,浏览器硬刷新(`Ctrl+Shift+R`)。
## 检查
```sh
pnpm run typecheck # 0 errors
pnpm test # 55 tests passing
pnpm run build # lib/index.js + lib/client.js
```
### 产物验证
- `lib/index.js` — Host bundle
- `lib/client.js` — Client bundle(CSS-modules inline,`d` 前缀 hash 防 CSS 类名数字开头)
- `cordis.patch.yml` — Bundle patch layer
## 持久化
Profile 状态通过 DSH settings seam 持久化到 `$DSH_HOME/settings.yaml` 的 `ya-subagent` 命名空间。cordis.yml 的 `profiles` 字段是组合 `base`(首次启动种子),运行时变更通过 `scope.replace()` 写入用户层。外部 yaml 编辑通过 `scope.watch` 热重载。
无 settings provider 的无头组装回退到内存状态(仅 cordis.yml 种子,不持久化)。
## RPC API
Profile CRUD 走 `/api` 通道上的 exact Fetch route(`ctx.connection.fetch.register`,与官方
dsh-client-file-upload 同模式)。不占用 `/api` 的单拦截器槽(该槽归 Typert gateway 所有);
信任栅栏与浏览器认证由 `/api` 载体统一执行。
| endpoint(wire method) | payload | result (ok) |
|----------|---------|-------------|
| `ya-subagent.profiles.list` | `{}` | `{ profiles: SubagentProfile[] }` |
| `ya-subagent.profiles.add` | `{ profile: SubagentProfile }` | `{ profiles: SubagentProfile[] }` |
| `ya-subagent.profiles.update` | `{ profile: SubagentProfile }` | `{ profiles: SubagentProfile[] }` |
| `ya-subagent.profiles.remove` | `{ id: string }` | `{ profiles: SubagentProfile[] }` |
| `ya-subagent.tools.list` | `{}` | `{ tools: { name, description }[] }` |
| `ya-subagent.sessions.repair` | `{}` | `RepairStats` |
URL 形如 `POST /api/ya-subagent.profiles.list`(Connection client-request envelope,响应为
server-response envelope)。业务错误返回 `{ ok: false, error: { code: 'internal', message } }`。
> 历史注:v0.3.x 走 `connection.rpc.handle('/ya-subagent', …)` 专用通道;dsh 0.1.5 的
> 专用通道注册在 web profile 拓扑下无法挂载(webserver 服务与 connection 是兄弟 loader
> 行,`rpc.handle` 内部的 `owner.webServer` 解析永远失败),浏览器侧表现为
> `transport failure for /ya-subagent/profiles.list: HTTP 405`。v0.4.0 起改用 exact
> Fetch route。
## 已知限制
- **旧会话不兼容**:`completed <label> subagent <id>` render 格式变更后,旧会话的结果文本无法被 `parseResult` 匹配,卡片不可点击。仅新会话(host 重启后)正常。
- **`yaSubagentProgress` stateVersion 2**:projection schema 变更(`activity` 字段 + `assistant/chunk` fold)需要 host 重启才能生效。
## 设计参考
- 官方 continuable subagent 设计:`.agents/notes/implemented/feature/2026-07-28-continuable-subagent-conversations.md`
- 插件开发指南:`plugin-development-guide.md`
Install
dsh plugin --profile web add github:HuanLinOTO/dsh-plugin-yet-another-subagent#f6a43f5fddece87f5ae1cab3bff5d3d45e6788d0
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install huanlin-dsh-plugin-yet-another-subagent from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.