DSH plugin 的 Slot 组合:cardinality、scope 与 props 推导怎么写

插件开发发布于 2026-10-17作者: DeepSeek Plugin 插件市场
DeepSeek HarnessDSH pluginSlotcardinalityscopeWeb UI
DSH plugin 的 Web UI Slot 系统怎么用:编译期 SlotMap 声明、四种 cardinality 与三种 scope、props 从声明推导而不是抄写,以及 effect 生命周期下的递归折叠。

**DSH plugin 的 Web UI 扩展不是「导出一个组件让别人 import」,而是一套类型化组合系统:SlotMap 在编译期声明槽位,功能插件通过 ctx.slots.register() 往里贡献,组件之间从不互相 import。 这套设计有两个直接后果:props 是从声明推导出来的,不要手抄成员;注册与声明跟随 effect 生命周期,拥有者卸载时贡献会被递归折叠。理解这两条,就能避开「组件拿不到会话」「重复注册报错」「卸载后残留 UI」这三类高频问题。

DSH plugin 的 Slot 声明与生命周期

一句话结论:声明一个 child 同时做三件事,且每个声明只能有一个存活 owner。

  1. 声明三效果:让 child key 生效、授权父 entry 调用 renderSlot/renderSlotChain、记录运行时 dispatch 规格。
  2. 唯一 owner:向未声明 slot 注册,或重复声明他人已拥有的 child,都会在插件激活时失败。
  3. root 是特例:唯一内建声明,也是唯一由 Cordis 服务自身渲染的 key;其余后代都通过父 entry 收到的 props 渲染。
  4. effect 生命周期:销毁 entry 会移除贡献并递归折叠它声明的 child slot。
  5. 跨包贡献:用 ctx.slots.inject(key, callback),回调在每段声明生命周期内运行,owner 重挂时自动重跑。

DSH plugin 的四种 cardinality:数量与寻址

一句话结论:single 取胜者、list 按 id 并列、keyed 按 key 匹配、chain 按 select 竞争。

cardinality行为适用
single单个 cell,渲染当前 priority 胜者有且只有一个实现的位置
list必填 id 定址,先按 order 再按注册顺序并列多个同等贡献
keyedowner 传 entryKey,匹配 cell 用该 key 的 props按实体寻址的贡献
chain每个 entry 提供 select(owner),第一个非空获选需要「谁能处理」的决策
  1. 别把 single 当列表:需要并列内容时声明 child slot。
  2. priority 语义:single/list/keyed 里是遮蔽优先级,chain 里是选举顺序;数值越小越先。
  3. 新增用新 id:增量贡献用新的 list id 或 keyed key;复用已有 cell 表示有意替换。
  4. chain 的 fallback:全部拒绝时渲染 owner 提供的兜底。

DSH plugin 的三种 scope:会话绑定要不要

一句话结论:root 只有一个根实例,session 要求确定会话,session-maybe 允许缺失。

  1. root:一个根作用域组件与 store 实例。
  2. session:要求可解析的外围 Provider binding,收到确定存在的 Session 值。
  3. session-maybe:继承外围 binding,但没有 binding 时仍渲染,Session 值可选。
  4. 子树的覆盖:声明 session/session-maybe child 时,PropsRenderSlots 会提供 SessionProvider;不传就继承,显式传引用或 undefined 只覆盖该子树。
  5. 重挂规则:严格 session entry 在 binding 代际变化时重挂;空白 session-maybe entry 接受首个 binding 时不重挂,后续代际变化或回到缺失才重挂。

DSH plugin 的组件 props:从声明推导,不要抄写

一句话结论:六类输入各有声明者,组件从类型推导 props,服务对象留在闭包里。

输入来源类型
owner 值与 scope 值SlotMap 条目与 scope adapterPropsRuntime<K>
获授权的 child renderer注册项的 children keysPropsRenderSlots<S>
共享视图状态注册项的 storePropsStore<H>
私有数据与 observable注册项的 inject factoryInjectFace<I>
本地化函数locale namespacePropsLocale<N>
chain 选中的值select 结果ComposedProps.matched
  1. 没有 ctx:组件永远收不到上下文对象。
  2. 父值走 owner 参数:父组件渲染时已知的值通过 renderSlot 的 owner 参数进入。
  3. 服务不暴露:service 与 model object 留在 apply 闭包里,只投影 callback 或 observable source。
  4. 本地化:用声明的 locale namespace,不要硬编码文案。

DSH plugin 的 Slot 排查注意事项

一句话结论:Slot 问题先分「没声明」「注册冲突」「拿不到值」三类。

  1. 注册报错 → 检查目标 slot 是否已声明、child 是否已被他人拥有。
  2. 重复注册 → 同一 id 第二次注册会抛错,检查是否在两个地方各注册了一次。
  3. 拿不到会话 → 检查 scope 是 session 还是 session-maybe,以及外层是否有 binding。
  4. 卸载后还在 → 注册没挂在 effect 上,或用了 inject 却没走回调。
  5. 列表顺序不对 → 检查 order,再看注册顺序。
  6. 修复状态如实:本文的声明效果、四种 cardinality、三种 scope 与六类输入均取自官方「Web Client Slots」页面;具体 slot key 与类型以官方包与你的版本为准。

来源:Web Client Slots、dsh-client-ui-slots README、客户端资源。

常见问题

DSH plugin 往别人的 Slot 里加内容,为什么要用 slots.inject?

DSH plugin 的注册与声明跟随 Cordis effect 生命周期:拥有者折叠时贡献会被移除。用 slots.inject 的回调会在每段声明生命周期内重新运行,拥有者重挂时贡献自动回来,不需要你手动补注册。

DSH plugin 里,single、list、keyed、chain 四种 cardinality 该怎么选?

DSH plugin 的 single 只渲染当前优先级胜者,list 用必填 id 并列,keyed 由 owner 传 entryKey 匹配,chain 让每个 entry 用 select 竞争唯一结果。要并列多个内容就声明 child slot,不要把 single 当列表用。

DSH plugin 里,session 和 session-maybe 两种 scope 的区别是什么?

DSH plugin 的 session 要求可解析的外围 Provider binding,并拿到确定存在的会话值;session-maybe 没有 binding 时仍可渲染,会话值是可选的。选错会让组件在缺少会话时直接不渲染。

DSH plugin 里,组件可以通过 props 拿到 ctx 吗?

不能,DSH plugin 的 slot 组件绝不会收到 ctx。父组件已知的值经 renderSlot 的 owner 参数进入,共享视图状态用声明的 store,服务与模型对象留在 apply 闭包里,只向组件投影 callback 或 observable。

DSH plugin 里,声明一个 child slot 会产生哪些效果?

DSH plugin 声明 child 会同时做三件事:让 child key 生效、授权父 entry 调用 renderSlot 或 renderSlotChain、记录运行时 dispatch 规格。每个声明只能有一个存活 owner,重复声明会在激活时失败。

相关术语

SlotMap
SlotMap 是 DSH plugin 的 Web UI 编译期注册表,包通过声明合并写入 key、cardinality、scope、owner props、keyed props 与可选的 inject face。运行时声明则是拥有组件在 children 中给出的条目。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/slots
cardinality(基数)
cardinality 决定一个 slot 能容纳几个贡献,取值为 single、list、keyed 或 chain。它只描述数量与寻址方式,与 scope 是两个独立维度。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/slots
scope(作用域)
scope 决定 slot 组件能否拿到会话绑定,取值为 root、session-maybe 或 session。root 只有一个根实例,session 要求确定的会话值,session-maybe 允许缺失。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/slots
chain cardinality
chain 是 DSH plugin 的一种 slot 基数:每个 entry 提供纯 select(owner) 函数,按优先级遇到的第一个非空结果获选并以 matched 传给组件,全部拒绝时渲染 owner 的 fallback。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/slots

来源