---
description: "dsh 的角色预设与模型池：模型只选角色，由用户的规则决定用哪个模型，失败按角色链逐级回退。"
---

# @snnh/dsh-role-config

[English](README.md) | 中文

这个 dsh bundle 给委派加了两条入口和一层决策：

- **角色预设**：模型按角色委派（`role: "premium"`），永远不知道背后是哪个模型。每个角色带模型可读的描述、优先级链，以及用户自己写的路由规则。
- **模型池**：模型可以直接点名的模型，每个都带用户写的描述。直连按原样执行，不参与回退。
- **路由规则**：在角色链首之前按顺序求值——提示词包含、正则、必需模态、最小上下文窗口、用户自己的能力标签。全不命中且开启 AI 路由时，由一次有界的路由器调用裁决；失败则回落链首。
- **优先级回退**：角色路径创建的子代理请求终局失败后，用同一请求改走链上下一个成员；链走完则原失败照常上报。
- **功能绑定**：上下文压缩与会话标题可以跟随某个角色，或保持 dsh 默认。

## 安装

```sh
dsh plugin --profile <profile> add @snnh/dsh-role-config
```

包已发布到 npm，上面的命令不需要构建步骤。git 安装（`github:snnh/dsh-role-config`）同样可用：构建产物（`lib/index.js`、`lib/client.js` 及其声明）随仓库提交，因此**不需要**构建脚本，也不需要 `allowBuilds` 放行。改动 `src/` 后用 `npm run build` 重新构建。

## 默认什么都不开

刚挂载时插件不注册任何工具，也不改动任何 agent：`exposure.delegateTool` 与 `exposure.listTool` 的缺省值都是 `false`，官方委派工具照常服务，直到操作者主动点名要可路由的那一条。打开这两个开关就是全部的开启动作：

```yaml
- id: role-config
  config:
    exposure:
      delegateTool: true
      listTool: true
    pool:
      - provider: deepseek-official
        model: deepseek-chat
```

## 唯一的前置条件

开启 `exposure.delegateTool: true` 后，本插件用官方 `subagent` 同名注册委派工具。插件启用时，agent 看到的就是这条可路由的工具；停用插件，官方工具随即恢复服务。遮蔽要求官方工具比 agent 更靠外一层，因此官方 `tool-subagent` 行必须带 `modelSelectionSettings: false`：

```yaml
- id: tool-subagent
  config:
    provider: spawn
    toolName: subagent
    modelSelectionSettings: false
```

那一行必须保持**启用**。为了腾出名字而停用它是一笔单向交易：此后一旦停用本插件，部署里就一个委派工具都没有了。其实并不需要：可路由的注册比预设作用域更靠内，因此它赢得这个名字，而官方工具依旧挂载着、随时可用。关闭接管（`delegateTool: false`，或设置页的**恢复官方委派工具**按钮——它一步完成"关开关并保存"）就把名字交还回去，插件顺手清掉官方行上遗留的 `disabled: true`。

profile patch 只能改到 profile 自己声明的行；出厂预设的行嵌在 `cordis:group` 里，而 patch 会整体替换该行 config，所以需要像 harness 自己的 overlay 那样重述预设行、只翻这一个字段（出厂清单见 `packages/bundle/web-app/presets/standard.patch.yml`，它变化时请同步这份副本）：

```yaml
- id: preset-standard
  config:
    id: standard
    order: 1
    plugins:
      # …出厂插件清单，原样保留…
      - id: delegation
        name: cordis:group
        group: true
        isolate: { workflowEngine: true }
        config:
          - id: tool-subagent
            name: '@deepseek-ai/dsh-tool-subagent'
            config:
              provider: spawn
              toolName: subagent
              modelSelectionSettings: false
```

开启模型选择时，官方工具会注册进每个 agent 自己的作用域，同作用域无法存在同名工具：这种情况插件会点名需要修改的行并保留官方工具，会话照常打开。若你更想保留官方配置，可用 `delegate.toolName` 改本插件的工具名。

## 在 LAN 地址上配置

设置文档默认只对回环页面开放，因此在 `http://<lan-ip>:<port>` 访问的部署里，模型页与所有插件页都会显示为不可用。若要在你实际使用的地址上配置本插件，请重述 `client-connection` 行并打开操作面：

```yaml
- id: connection
  config:
    trustedHosts: !!js ctx.webRuntime.trustedHosts
    operatorSurface: trusted
```

patch 会整体替换该行 config，所以 `trustedHosts` 要一并保留。页面只会在这之后、且访问令牌校验通过时才被提供，它发起的每个请求仍要过 Host/Origin 围栏与会话检查；改变的只是设置页与插件页终于能渲染。

## 配置

Web 侧栏打开 **Plugins**，选择 **Role Config**。页面编辑同一份 `role-config` 设置：模型池与描述、角色预设与链/规则、开关（暴露面、回退、AI 路由）、功能绑定、委派接线。

## 模型能看到什么

| 暴露面 | 内容 | 时机 |
| --- | --- | --- |
| `list_model_roles` | 角色 id + 描述；池内路由 + 描述 | 仅模型主动调用时 |
| 系统提示 | 同一份目录的紧凑版 | 仅开启 `exposure.sessionStart` |
| `subagent`（`role`） | 不含所选模型的任何信息 | 始终 |

角色的成员、规则与路由器的裁决**从不**到达模型。

## 限制

- 直接指定路由不走回退；主 agent 自身的请求也不回退。
- agent team 成员继承 Lead 的路由，本插件只能对成员做失败回退，不能挑模型。
- 功能绑定写的是目标行的配置，本身没有回退。
