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

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

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

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

  • 最终的插件树是按照固有的顺序先后应用插件补丁文件构建而成;
  • 每个补丁文件提供一组PatchOptions列表,一个PatchOptions对象代表一个插件(组);
  • 插件补丁文件可以利用-insert在根节点或者在现有的插件组中添加一组插件(组),插入的插件(组)体现为一个EntryOptions对象;
  • PatchOptions和EntryOptions不仅可以指定作为标识的id和作为包名/模块的name,还可以分别利用confgi、inject和intercept指定插件配置、注入的依赖服务列表和针对服务的配置,基于利用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提供的补丁文件能够按照我们的预期参与到插件树的构建流程,我们定义了如下两个补丁文件,分别命名为overlays1和overlays2。这两个补丁同样注册了foo和bar两个插件,前者至于顶层的根节点,后者分别添加到由ComposedProfile.bundlePatches创建的组group1和group2。我们将这两个文件保存到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添加了针对foo和bar的两个插件。由于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-tools和cordis: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]
相关推荐
寻道码路4 小时前
大模型工程化实战(十六):政企国产化避坑——合规/信创名录/私有化运维/国产硬件适配/原厂支持这五道关怎么过
大模型·agent·信创·rag·ai工程化·国产化替代·政企ai落地
Query*6 小时前
深入浅出LangGraph【一】_基础篇
python·ai·langchain
Ian_zhy6 小时前
workbuddy-to-dsh使用教程
workbuddy·harness
Blockbuater_drug7 小时前
ADMET 预测从图神经网络到 DeepSeek RAG 解释:CPU 全流程实测跑通
图神经网络·deepseek·admet 预测·rag 解释·tdc 数据集
张忠琳7 小时前
【hermes-agent】Hermes Agent 自我进化原理之一
ai·agent·hermes
Ai-_Man7 小时前
您您这可以把Grok的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。AI导出鸭
javascript·人工智能·ai·小程序·电脑
Harzerr7 小时前
AI行业日报|2026-10-04:5个热点事件
ai·行业动态·技术趋势
Bug收容所7 小时前
学习LangChain day1
学习·langchain·llm·agent
汤姆yu8 小时前
Gemini 4 Argon模型综述:技术、能力与实际使用指南
网络·安全·web安全·ai·大模型
搭贝8 小时前
上厕所的时间搭好一套系统:AI自动生成实测
开发语言·人工智能·低代码·ai·php·搭贝