[DeepSeek Harness深度拆解-04]完整的插件配置树如何构建?

通过前面两篇文章针对Profile的介绍(Profile究竟是什么?创建一个新的Profile提供自定义插件),我们知道了所谓的Profile本质上就是构建了一组用来提供插件的配置,但是最终应用到Cordis上的插件不限于此,它还有其他的来源。这篇文章就来不起最后这张拼图。

1. Profile提供的两层插件配置

回顾一下前面的两篇文章,总计下它主要提供的如下的知识点:

  • 最终的插件树是按照固有的顺序先后应用插件补丁文件构建而成;
  • 每个补丁文件提供一组PatchOptions列表,一个PatchOptions对象代表一个插件(组);
  • 插件补丁文件可以利用-insert在根节点或者在现有的插件组中添加一组插件(组),插入的插件(组)体现为一个EntryOptions对象;
  • PatchOptionsEntryOptions不仅可以指定作为标识的id和作为包名/模块的name,还可以分别利用confgiinjectintercept指定插件配置、注入的依赖服务列表和针对服务的配置,基于利用isolate构建独立的隔离域(本质上就是根据指定的名称调用isolate方法来创建子Context);
  • Profile提供了两组PatchOptions列表,分别以如下的两种方式构建:
    • 利用package.json注册包提供的插件补丁文件构建而成;
    • 利用自身的cordis.patch.yml补丁文件构建而成。

2. 插件配置树的额外两层

DSH被启动并完成初始化流程后,除了通过指定Profile构建的两层插件配置,还包括如下两层:

  • 在DSH运行时目录(通过环境变量DSH_HOME定义,默认位置为~/.dsh或者%userprofile%.dsh)下定义的补丁文件;
  • 用户启动DSH以命令行参数--patch指定的补丁文件(这个采用可以服用,意味着可以指定一组补丁文件)。

上述两组补丁文件构建的PatchOptions会和Profile对象一起,组成一个ComposedProfile对象,该接口对应的定义如下:

typescript 复制代码
interface ComposedProfile {
  profile: Profile
  bundlePatches: PatchOptions[]
  homePatches: PatchOptions[]
  overlays: PatchOptions[]
}

四个字段成员说明如下:

  • profile: 构建的Profile对象;
  • bundlePatches :由注册到Profile的包提供的补丁文件构建的一组PatchOptions列表(PatchOptions列表的列表)被打平后的结构;
  • homePatches :由在DSH运行时目录提供的补丁文件构建的PatchOptions列表;
  • overlays : 由命令行参数--patch提供的补丁文件构建的PatchOptions列表。

上述作为四个来源的PatchOptions列表可以视为四个层次,在生成最终插件树时,会按照既定的顺序提取每个PatchOptions并应用到当前构建的这颗树上。具体的提取顺序如下:

  • ComposedProfile.bundlePatches:
  • ComposedProfile.profile.patchPath
  • ComposedProfile.homePatches
  • ComposedProfile.overlays

3. 注册homePatches

创建一个新的Profile提供自定义插件中,我们已经创建了一个用来提供自定义插件的Profile,我们现在来看看如何我们补齐其他两种类型的补丁,最后构建的插件树是否会改变。为此我们在%userprofile%.dsh目录下创建一个补丁文件cordis.patch.yml,提供如下的内容:

yaml 复制代码
- insert:
    - id: plugin7
      name: '@jaydenai/foo'
      config:
        source: '$DSH_HOME/cordis.patch.yml'
- id: group1
  insert:
    - id: plugin8
      name: '@jaydenai/bar'
      config:
        source: '$DSH_HOME/cordis.patch.yml'

我们在这个补丁中提供了两个插件,其中插件foo被至于根节点,另一个插件bar被添加到现有的组group1中。为了能够在运行时确定插件的来源,我们通过提供的配置将source指定为$DSH_HOME/cordis.patch.yml。接下来我们按照如下的方式执行命名npx tsx apps/cli/src/bin.ts --profile test以源码启动DSH,并将profile设置为test。从输出可以看出多出了两个来源匹配的插件被执行,输出的结构与与上面的定义相符。

bash 复制代码
PS E:\dsh\deepseek-harness> npx tsx apps/cli/src/bin.ts --profile test
npm notice run @deepseek-ai/dsh-root@0.1.5-alpha.2 npx
npm notice run tsx apps/cli/src/bin.ts --profile test
Loader>Include>foo[package.json]
Loader>Include>foo[cordis.patch.yml]
Loader>Include>foo[$DSH_HOME/cordis.patch.yml]
Loader>Include>bar[package.json]
Loader>Include>Group>bar[cordis.patch.yml]
Loader>Include>Group>bar[$DSH_HOME/cordis.patch.yml]
Loader>Include>Group>baz[package.json]
Loader>Include>Group>Group>qux[package.json]
Loader>Include>Group>Group>baz[cordis.patch.yml]

4. 注册overlays

我们进一步来验证利用命令行参数--patch提供的补丁文件能够按照我们的预期参与到插件树的构建流程,我们定义了如下两个补丁文件,分别命名为overlays1overlays2。这两个补丁同样注册了foobar两个插件,前者至于顶层的根节点,后者分别添加到由ComposedProfile.bundlePatches创建的组group1group2。我们将这两个文件保存到d:\下。

d:\overlays1:

yaml 复制代码
- insert:
    - id: plugin9
      name: '@jaydenai/foo'
      config:
        source: overlays1
- id: group1
  insert:
    - id: plugin10
      name: '@jaydenai/bar'
      config:
        source: overlays1

d:\overlays1:

yaml 复制代码
- insert:
    - id: plugin11
      name: '@jaydenai/foo'
      config:
        source: overlays2
- id: group2
  insert:
    - id: plugin12
      name: '@jaydenai/bar'
      config:
        source: overlays2

我们依然按照上面的方式启动DSH,不过这次我们通过两次使用命令行参数--patch分别指定了上述两个补丁文件。由它们提供的四个插件同样出现在最终的输出结果中。

bash 复制代码
PS E:\dsh\deepseek-harness> npx tsx apps/cli/src/bin.ts --profile test --patch d:\overlays1.yml --patch d:\overlays2.yml  
npm notice run @deepseek-ai/dsh-root@0.1.5-alpha.2 npx
npm notice run tsx apps/cli/src/bin.ts --profile test --patch d:\overlays1.yml --patch d:\overlays2.yml
Loader>Include>foo[package.json]
Loader>Include>foo[cordis.patch.yml]
Loader>Include>foo[$DSH_HOME/cordis.patch.yml]
Loader>Include>foo[overlays1]
Loader>Include>foo[overlays2]
Loader>Include>bar[package.json]
Loader>Include>Group>bar[cordis.patch.yml]
Loader>Include>Group>bar[$DSH_HOME/cordis.patch.yml]
Loader>Include>Group>bar[overlays1]
Loader>Include>Group>baz[package.json]
Loader>Include>Group>Group>bar[overlays2]
Loader>Include>Group>Group>qux[package.json]
Loader>Include>Group>Group>baz[cordis.patch.yml]

5. 包含文件的使用

在定义补丁问文件的时候,插件的节点被我们设置成包名、插件组的名称被统一设置成预定义的cordis:group。其实我们还可以将节点名称设置为cordis:include将另一个补丁文件引进来。比如在d:\include.yml添加了针对foobar的两个插件。由于SDH针对包的解析会在该文件所在的目录进行,所以我们直接使用定义插件的源文件。除此之外,包含就隐含插入的意思,所以不能在外面在套一层insert。我们通过配置插件将source设置成include以示来源。

yaml 复制代码
- id: plugin13
  name: file:///E:/dsh/deepseek-harness/packages/demo/foo/lib/index.js
  config:
    source: include
- id: plugin14
  name: file:///E:/dsh/deepseek-harness/packages/demo/bar/lib/index.js
  config:
    source: include

我们修改test Profile所在目录的补丁文件cordis.patch.yml,并添加了一个id和name分别为include-extra-toolscordis:include的节点,在设置的配置中利用path字段只想上面这个include.yml文件(DSH要求文件路径严格采用为file:///为前缀的模式)。

yaml 复制代码
- insert:
    - id: plugin5
      name: '@jaydenai/foo'
      config:
        source: cordis.patch.yml
    - id: include-extra-tools
      name: 'cordis:include'
      config:
        path: 'file:///d:/include.yml'
- id: group1
  insert:
    - id: plugin6
      name: '@jaydenai/bar'
      config:
        source: cordis.patch.yml
- id: group2
  insert:
    - id: plugin7
      name: '@jaydenai/baz'
      config:
        source: cordis.patch.yml

我们依然按照上面的方式启动DSH。会发现d:\include.yml包含的两个插件会出现在最终的输出结果中(最后两个)。

bash 复制代码
PS E:\dsh\deepseek-harness> npx tsx apps/cli/src/bin.ts --profile test --patch d:\overlays1.yml --patch d:\overlays2.yml
npm notice run @deepseek-ai/dsh-root@0.1.5-alpha.2 npx
npm notice run tsx apps/cli/src/bin.ts --profile test --patch d:\overlays1.yml --patch d:\overlays2.yml
Loader>Include>foo[package.json]
Loader>Include>foo[cordis.patch.yml]
Loader>Include>foo[$DSH_HOME/cordis.patch.yml]
Loader>Include>foo[overlays1]
Loader>Include>foo[overlays2]
Loader>Include>bar[package.json]
Loader>Include>Group>bar[cordis.patch.yml]
Loader>Include>Group>bar[$DSH_HOME/cordis.patch.yml]
Loader>Include>Group>bar[overlays1]
Loader>Include>Group>baz[package.json]
Loader>Include>Group>Group>bar[overlays2]
Loader>Include>Group>Group>qux[package.json]
Loader>Include>Group>Group>baz[cordis.patch.yml]
Loader>Include>Include>foo[include]
Loader>Include>Include>bar[include]
相关推荐
Csvn1 小时前
第 23 章 性能、成本与部署
人工智能·aigc·agent
为自己_带盐1 小时前
我把自己做安全审查的一套方法,做成了一个 AI Skill
ai·安全性测试
海带紫菜菠萝汤2 小时前
大模型本地部署踩坑实录:显存不足、依赖冲突、推理慢的完整排查
人工智能·ai·大模型
牛油果子哥q2 小时前
LLM安全与内容风控全栈落地: Prompt注入、越狱攻击、幻觉风控、敏感词过滤、C++风控网关、多级审核体系、线上攻防实战
ai·llm
鲲逸鹏3 小时前
聊聊最近很火的FDE
ai·agent
NetFarmerSG4 小时前
CRM 自动化与 Agentic AI:从规则执行到目标驱动
ai·crm系统·ai agent·hubspot
DeepAgent4 小时前
AI Agent 面试篇(02):面试路线总览——每一关考什么、题什么样、要准备什么
面试·agent
七牛云行业应用5 小时前
2026 年 9 月 Coding Agent Harness 选型完整指南:30 个工具、SDK 与运行时
人工智能·agent·ai编程
武子康5 小时前
小智服务端怎样组织 ASR、LLM、TTS?先追本次连接实际使用的对象
人工智能·llm·agent