← 核心插件深度解析索引 / 整体架构解析
@deepseek-ai/dsh-system-prompt · packages/core/system-prompt

dsh-system-prompt — 提示词组装注册表

插件贡献有序的 section、动态 context、tool schema 与命名变量;agent 循环每步组装一次并把结果渲染为完整模型提示词。 agent 作用域的 persona 可 shadow 全局默认。

ctx key: ctx.systemPrompt 2 个 src 文件 · 695 行(最小核心包) Service 类插件(默认导出 SystemPrompt) Config: includeHarnessIdentity · includeRuntimeContext · persona · toolOrder

01包定位与入口

内容
ServiceSystemPrompt extends Service,super(ctx, 'systemPrompt');无 inject(纯 Service 插件)
ConfigincludeHarnessIdentity(默认 true,身份 opener)/ includeRuntimeContext(默认 true)/ persona(全局 order-0 persona 模板,空则丢弃)/ toolOrder(显式模型可见工具顺序,必须含恰好一个 '<unlisted-tools>' rest 项,省略则字典序)
事件system-prompt/assemble(waterfall,scope 过滤)+ system-prompt/change(emit,全局 unfiltered —— 全局变更影响每个 scope)
常量PERSONA_SECTION = 'deployment:persona'PERSONA_ORDER = 0TOOL_ORDER_REST = '<unlisted-tools>'

02核心接口

// 五个注册 API(全部走 ScopedLayers.effect → 返回精确 disposer)
section(section: PromptSection): () => void
context(context: PromptContext): () => void          // 动态 context 贡献,按 order 升序
suppressRuntimeContext(): () => void
tools(provider): () => void                              // { schemas, knownNames? }
variable(name, provider): () => void                     // /^[a-z][a-z0-9_]*$/

assemble(context?: AssembleContext): Promise<PromptAssembly>

03关键机制深度解析

assemble() 组装顺序与 shadowing(index.ts:467-542)

scope 链
chainLayers(scope):最远祖先在前,精确 scope 最后
runtimeContextSuppressed 判定
全局层任意 suppressor 非空 或 链上任意层非空 → contexts 恒为 []
变量合并
全局先入,scope 链最远优先逐层覆盖 —— 最近的 scope 赢得同名变量(shadowing)
▼ sections/contexts:merge() 同名覆盖;tools:全部 provider 逐个求值,schema 做 structuredClone 脱拷
稳定排序
sections/contexts 按 order 升序;tools 走 orderTools(字典序或 toolOrder)
system-prompt/assemble 瀑布
scopeTarget(this, scope) 分派;监听者返回值权威;complete section 是最终约束(waterfall 后被还原为唯一 section);runtimeContextSuppressed 时丢弃监听者新增 contexts
◆ 谁是最终权威 — 瀑布监听者可以改 sections/contexts/tools/variables,但两个约束在 waterfall 之后强制生效: complete section(>1 个同时有效 → assemble 拒绝)与 runtimeContextSuppressed(contexts 强制 [])。

工具排序 orderTools(index.ts:164-178)

toolOrder === undefined → 字典序(码元比较,机器无关);配置了 toolOrder → 未注册名抛错(load 时只校验形状,未注册名在首个 turn 才抛)、 listed 项按序放置、未列出工具在 rest 项处以字典序插入。provider 返回保留名 TOOL_ORDER_REST 本身 → 抛错。

渲染与严格插值(index.ts:258-295)

invariant(system-prompt/src/invariant.ts)

{ global: true, prepend: true }system-prompt/assemble,对瀑布权威返回值校验:section/context 名称非空且层内唯一、text 为 string;tool 名称非空;变量名匹配、值为 string 或 undefined。

04自定制插件指南

  1. 注册自己的 section:ctx.systemPrompt.section({ name, order, text, complete? });命名约定 owner:role(harness:identity / deployment:persona / tool:bash);order 分带 -100 身份、0 persona、100-199 工具指导 —— 同 order 按注册顺序,确定性依赖分带约定
  2. 替换已有区块:同层同名重复注册抛错;scoped 同名 section shadow 全局同名(agent preset 注册 deployment:persona 即替换部署 persona);经 agent.ctx 注册即 agent-local;要彻底移除(而非替换)只能在瀑布里改 assembly.sections(无删除 API)
  3. 整体接管提示词:complete: true 的 section 在 waterfall 后成为唯一 section(工具/context/变量仍解析)
  4. 工具:ctx.systemPrompt.tools(ctx => ({ schemas, knownNames? })) —— ToolRuntime 自动注册自身为 provider;restriction 后可见集合放 schemas,knownNames 放 restriction 前全集供 toolOrder;不要返回 '' 名
  5. 变量:ctx.systemPrompt.variable('cwd', ctx => process.cwd()),文本里 {{cwd}} 引用;loop 已注册 model/cwd;返回 undefined = 本组装无值,引用它的 section 渲染失败
  6. 拦截组装:ctx.on('system-prompt/assemble', ...)(waterfall,必须调 next());从 agent.ctx 注册只影响该 agent

05关键陷阱与约定