第 2 卷

loader 还会把这个 Entry 记在 fiber 上(fiber.entry),让图纸和实物永远对得上账—— 后面讲组的时候,你还会用到它。
config 的安检:schema
config 就是 YAML 里 config: 块的内容,看起来是“原样传进来”。但 Cordis 允许插件在调用 apply 之前先给它过一道安检:声明一张 schema,校验类型、补齐默认值。给
logger 加一张 schema:
复制代码
| 1 | //给插件配一张config的"身份证":类型+校验+默认值 |
|---|---|
| 2 | import{Context}from'@deepseek-ai/cordis' |
| 3 | importzfrom'@deepseek-ai/schemastery' // cordis生态的Standard Schema验证器 |
| 4 | //(HMR插件依赖里已带,无需另装) |
5 6export const name = 'logger'
7
| 8 | exportinterfaceConfig{ | // TS类型:给消费方类型提示 |
|---|---|---|
| 9 | level:string | |
| 10 | targets:string[] |
16})
17
| 18 | exportfunctionapply(ctx:Context,config:Config) { |
|---|---|
| 19 | console.log(`[logger]启动(level=${config.level})`) // config已校验、默认值已补 |
| 20 | } |
Cordis 会先校验、再调用 apply:校验通过才执行,未提供的字段由 schema 默认值补齐 ——所以 apply 收到的永远是一份完整、验证过的配置(比如 YAML 里只写 level:
debug,targets 也会被默认值补上)。
反过来,在你已经给 logger 挂上这张 schema 的前提下,如果再把类型写错:
复制代码 1- id: logger
2name: './plugins/logger.ts' 3config:
4level: 123# 错:level 应该是 string
Cordis 在加载时就抛 ValidationError,错误精确到字段(实测输出:invalid config: $.level expected string but got 123 (at level)),这个 fiber 随
之进入 FAILED 状态。
两条设计原则
- 可调参数不硬编码:随部署环境变化的值(如日志级别、接口地址)应放在 cordis.yml
的 config 块中,不要写死在代码里。判断标准:调整这些值时,只需修改 YAML,无需改动代码、重新构建或发布。
- 配置错误要响亮:需要严格校验时,用 schema 表达完备约束,让非法配置在加载时就失
败(FAILED + 明确的 ValidationError),而不是静默出错。schema 不是强制项,但该用的时候要严格。
复制代码 1# 扩充版:树长高了
2- id: logger 3name: './plugins/logger.ts'
4config:
| 5 | level: !!js process.env.LOG_LEVEL ??'info' | #①动态取值:环境变量不存在时回退到 |
|---|---|---|
| 6 -id: shell | #②根级再挂一个插件(与logger平 | |
| 7 | name:'./plugins/shell.ts' | |
| 8 | config: | |
| 9 | provider: deepseek | |
| 10 | model: deepseek-chat | |
| 11 -id: tenant-a | #③组:树干节点,内部再挂子插件 | |
| 12 | name:'@deepseek-ai/cordis-plugin-group' | |
| 13 | group:true | |
| 14 | config: | |
| 15 | -id: a-chat | |
| 16 | name:'./plugins/chat.ts' | |
| 17 -id: spare | #④备用条目:保留在配置里,但暂不挂 | |
| 18 | name:'./plugins/chat.ts' | |
| 19 | disabled:true |
这一讲要拆的四个新东⻄,分散在这份配置的不同条目上,我们逐个看。
id:条目的稳定身份。不写 id 也能挂载(loader 会随机生成一个),但写了才谈得上 “对账”:全名按祖先前缀 + 自己的 id 拼,tenant-a 组里的 a-chat 全名是 tenant-
a:a-chat。
disabled:留着配置,但暂不挂载。保留在配置里方便日后一键启用,运行时直接跳过。
它还会“连坐”——组被 disabled,组内子条目即使自己没写也一并停用。但组条目自身永远 enabled:组的职责是“包含”,不能把自己关掉。
!!js:让配置变成程序。level: !!js process.env.LOG_LEVEL ?? 'info' 会被解析成一个 JS 表达式,在条目自己的上下文里惰性求值,环境变量、条件分支都能直接写
进 YAML。要记清一个边界:!!js 只在 config 块和条目的 disabled 字段内生效;