运行时自省与动态 Cordis 插件
一句话版:
@deepseek-ai/dsh-tool-cordis让模型先查询当前 Host/Client 能力,再定义一个不可变 Package,并通过稳定pluginId运行、更新、检查、停止或永久删除动态 Cordis 插件。
这套机制由四个包协作:
| 包 | 职责 |
|---|---|
@deepseek-ai/dsh-tool-cordis | 注册七个模型工具和 @pluginId 引用注入 |
@deepseek-ai/dsh-cordis-host-runner | 保存动态插件、Package、版本指针与 Host 运行状态 |
@deepseek-ai/dsh-cordis-client-runner | 在浏览器侧授权并运行 Client 半部 |
@deepseek-ai/dsh-client-ui-cordis | 在会话中渲染定义、启动和状态卡片 |
源码入口是 packages/extensions/tool-cordis/src/index.ts。实际注册表以 TypeScript 为准。
一、七个工具
| 工具 | 作用 | 是否改状态 |
|---|---|---|
cordis_inspect_list | 列出 Host 与 Client 已知的 Inspect Provider、方法和 schema | 否 |
cordis_inspect_query | 调一个 Provider 声明的只读查询 | 否 |
cordis_inspect_self | 查看当前 Session 拥有的动态插件、Package、版本与诊断 | 否 |
cordis_define | 记录一个新的不可变 Package;只校验,不运行 | 是 |
cordis_run | 首次运行、重启、回滚或更新到指定 Package | 是 |
cordis_stop | 停止当前运行,保留插件、Package、授权和版本指针 | 是 |
cordis_undefine | 永久删除插件及其所有 Package、授权和指针 | 是 |
旧的 cordis_inspect / cordis_mount / cordis_unmount 已由这套版本化生命周期取代。
二、先 Inspect,再写代码
cordis_inspect_list
先取得当前运行时真实存在的 Provider:
cordis_inspect_list
每项会给出:
platform:host或client- Provider id 与用途
- 可用的只读方法
- 每个方法的输入/输出 schema
cordis_inspect_query
只能使用 list 返回的精确名字:
platform: host
provider: Service
method: listService
input: {}
Host 查询本地执行;Client 查询等待浏览器页面响应。Inspect 只能读取契约、服务、事件、Builtin、Slot、token 或当前树,不能代替业务 Service 调用,也不能修改运行时。
推荐顺序:
cordis_inspect_list- 用导航型查询找到精确 service/event/slot
- 再对精确目标查询完整契约
- 最后写
cordis_define
三、cordis_define:创建不可变 Package
新插件只提交 3–6 位小写英文语义前缀,Host 负责生成唯一 id:
plugin:
kind: new
idPrefix: echo
name: Echo tool
purpose: Register a small echo capability
code:
host: |
return {
name: 'echo-package',
inject: [],
apply(ctx) {
// 使用 inspect 得到的真实 Cordis API
}
}
更新已有插件时:
plugin:
kind: existing
pluginId: echo-1
name: Echo tool v2
purpose: Add the second behavior
code:
host: "return { name: 'echo-v2', inject: [], apply(ctx) {} }"
关键约束:
- 至少提供
code.host或code.client之一 - 内容是返回 Cordis Plugin 的普通 JavaScript function body
- 不转换 TypeScript、JSX 或
import - Package 不可变;更新会追加 Package,不覆盖旧版本
define只做参数/语法校验并保存源码,不申请授权、不执行apply、不移动当前版本
成功返回稳定 pluginId 和精确 packageId。下一步必须显式 cordis_run。
四、cordis_run:运行、更新与回滚
pluginId: echo-1
packageId: pkg-2
mode: update
mode 只有两种:
run: 首次启动、重启当前版本或回滚update: 从当前版本切到另一个 Package
Client Package 首次运行可能返回 awaiting-approval;已授权的运行可能返回 starting 并在浏览器中异步继续。工具调用结束不代表 Client 半部已经完成。
版本指针语义:
- 只有 Host/Client 全部成功后才更新
currentPackageId - 启动中目标记录为
nextPackageId - 技术失败保留旧 current 与目标 next,便于检查、修复和重试
- 用户拒绝授权后,不重复发起相同授权请求
五、cordis_inspect_self:检查自己的版本和故障
cordis_inspect_self # 当前 Session 的插件摘要
cordis_inspect_self pluginId:"echo-1" # 版本指针、最近运行、Package 列表
cordis_inspect_self pluginId:"echo-1" packageId:"pkg-2"
最后一种会返回该不可变 Package 的 Host/Client 源码和运行诊断。packageId 不能脱离 pluginId 单独查询。
消息里写 @echo-1 时,agent/pre-step 会注入该插件当前引用;处理引用、修复异步失败或追加版本前,应先 inspect 精确 Package。
六、停止与永久删除
cordis_stop
停止当前运行并取消未完成的授权/启动请求,但保留:
- 插件和全部 Package
- Client 授权
currentPackageId/nextPackageId- 后续重启、更新和回滚能力
对已经停止的插件重复调用仍成功。
cordis_undefine
先停止活动运行,再永久删除插件、Package、授权和版本指针。之后旧 pluginId、packageId 与 @pluginId 引用全部失效;只在明确放弃全部版本时使用。
七、Host/Client 双半部流程
动态对象归当前 Session 所有,不再是旧实现中跨会话共享的一张临时挂载表。浏览器半部仍受页面连接、授权和异步生命周期约束。
八、验证
# 官方源码中确认七个注册名
rg -n "name: 'cordis_" packages/extensions/tool-cordis/src/index.ts
# 确认三个 runner/UI 包已进入 Web 组合
dsh web --dump-config | grep -E "cordis-(host|client)-runner|client-ui-cordis|tool-cordis"