跳到主要内容
路径文档

设置系统

一句话版ctx.settings 是运行时用户配置服务:用户在 UI/Settings 里改的东西存进 ~/.dsh/settings.yaml(由 dsh-settings-file 文件提供者热发布),settings/document-updated 事件让 UI 和插件同步。

这一篇说明白"patch 静态配置之外、用户运行时可改的那一层"。

一、这是哪一层

patch 层settings 层
谁写部署方(cordis.patch.yml)用户(UI / 文件)
内容静态配置/挂载运行时用户设置
载体cordis.patch.yml~/.dsh/settings.yaml
变更改文件重启动热发布,settings/document-updated

patch 和 settings 是两条配置缝,互补(见 配置)。

二、文件提供者:settings-file

dsh-settings-file 是默认实现,一个 YAML/JSON 文档承载每个 namespace 的 section:

字段默认说明
pathsettings.yaml(harness home 下)文档路径;扩展名选格式(.yaml/.yml/.json)
dshHome$DSH_HOME~/.dshpath 缺省时的 harness home
watchtrue监听文档,热发布外部编辑
debounceMs100写 settle 窗口(ms)

行为要点:

  • 启动 fail-loud,reload 保 last-good:存在的非法文档 → 插件加载失败;直播中的不可读编辑 → warn 并保留最后好的 section;缺失文档 → 每个 namespace 从 defaults+base 解析
  • 每次写都是 read-modify-write:先重读文档、发布差异,再写:不会复活陈旧文档或丢未观察的兄弟 section
  • 写持有跨进程写锁(*.lock sibling,wx 创建,2s 获取上限)
  • 原子、owner-only、防 symlink:渲染用随机后缀 temp(0600)再 rename 覆盖
  • YAML 编辑是叶级 diff:只改变化的值/删移除的键,保留注释锚点格式
  • documentPath 是解析后的绝对路径:ctx.settings.documentPathresolveSpec() 文件名;浏览器只拿到可用性标志,永不重建 $DSH_HOME、永不提交文件系统目标
  • 自身写靠内容去重:provider 缓存最后一份好文本,watcher 事件内容等于缓存(含自己的写)时是 no-op
  • 无值间接引用:section 存字面值,${env:VAR} 式密钥引用是 deferred 的 seam 层特性

三、surface:插件怎么用

import { settingsNamespace } from '@deepseek-ai/dsh-settings'
import z from '@deepseek-ai/schemastery'
import { Context } from '@deepseek-ai/cordis'

const ns = settingsNamespace('my-plugin')
const schema = z.object({
greeting: z.string().default('你好'),
maxItems: z.number().step(1).min(1).default(10),
})

export function apply(ctx: Context) {
const scope = ctx.settings.register(ns, schema, { /* base? */ })
// 解析顺序: schema默认 → composition base → 用户层
// scope.get() / scope.update({...}) / scope.watch(...)
}
  • register(ns, schema, {base?}) 返回 owner SettingsScope(get/watch/update)
  • 注册是 effect:dispose 该 fiber 会移除 namespace 与观察者
  • 存储的 section 被 schema 拒绝 → 注册失败;重复 namespace → fail loud
  • 完整示例见 配置与发布 的"运行时用户配置"

四、内置 namespace:agent-default-model

agent-default-model 是 DSH 自带的设置 section,由 dsh-agent-default-model 服务(ctx.agentDefaultModel)提供:

  • currentSelection() 返回一个 detached { provider, model, reasoningEffort? } 选择,给新建 Agent 用
  • saveSelection(selection) 保存完整用户选择;没有 settings provider 时是 no-op,组合里的部署默认保持生效
  • 部署默认写在插件 config(必填 { provider, model }),是 settings section 的 base;挂载 settings provider 后用户选择覆盖其上,下次 currentSelection() 读取即生效
  • reasoningEffort 只属于 settings section、不进插件 config:完整保存的选择在下一个模型没有 effort 时可以清掉它,而 composition 值会被再次继承
  • 服务不校验目录成员资格:provider route 可能服务一个未登记的模型,真正开模型请求的消费方负责可用性诊断
# ~/.dsh/settings.yaml
agent-default-model:
provider: deepseek-official
model: deepseek-v4-flash

直接入口(如 dsh --profile headless)与 Host 侧入口(如 ApiProxy)读同一个服务,不各自维护 provider/model 默认值。

五、事件

  • settings/document-updated:ctx.settings 值变化
  • 第三方插件/UI 监听它刷新;也触发 credentials/updated(若含凭据引用)

六、验证

# 看设置文档(用户可改的那层)
cat ~/.dsh/settings.yaml
# 组合里看 settings 服务
dsh web --dump-config | grep -i settings

下一步