dsh-plugin-prompt-tool 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +11 -9
  2. package/engine/anchor-match.mjs +38 -12
  3. package/engine/anchor-turn.mjs +68 -0
  4. package/engine/classify-task.mjs +35 -0
  5. package/engine/code-presentation.mjs +103 -0
  6. package/engine/compositions/library/anchor-turn.yml +10 -0
  7. package/engine/compositions/library/bootstrap-filesystem.yml +1 -1
  8. package/engine/compositions/library/code-presentation.yml +8 -0
  9. package/engine/compositions/library/command-goal.yml +11 -0
  10. package/engine/compositions/library/compaction.yml +1 -1
  11. package/engine/compositions/library/context-gate.yml +1 -2
  12. package/engine/compositions/library/cot-drip.yml +11 -0
  13. package/engine/compositions/library/custom-bash.yml +1 -1
  14. package/engine/compositions/library/delegation.yml +11 -7
  15. package/engine/compositions/library/deliberation-gate.yml +11 -0
  16. package/engine/compositions/library/persistent-shell.yml +25 -2
  17. package/engine/compositions/library/persona.yml +6 -2
  18. package/engine/compositions/library/planning.yml +1 -1
  19. package/engine/compositions/library/prompt-config-engine.yml +1 -1
  20. package/engine/compositions/library/run-code-env.yml +1 -1
  21. package/engine/compositions/library/skill-filesystem.yml +1 -1
  22. package/engine/compositions/library/skill-search.yml +1 -1
  23. package/engine/compositions/library/str-replace-editor.yml +2 -2
  24. package/engine/compositions/library/tool-ask-user.yml +1 -1
  25. package/engine/compositions/library/tool-bash.yml +1 -1
  26. package/engine/compositions/library/tool-bootstrap.yml +1 -3
  27. package/engine/compositions/library/tool-config-engine.yml +9 -0
  28. package/engine/compositions/library/tool-filter.yml +3 -7
  29. package/engine/compositions/library/tool-fs-search.yml +1 -1
  30. package/engine/compositions/library/tool-fs.yml +1 -1
  31. package/engine/compositions/library/tool-goal.yml +1 -9
  32. package/engine/compositions/library/tool-jobs.yml +1 -1
  33. package/engine/compositions/library/tool-pwsh.yml +1 -1
  34. package/engine/compositions/library/tool-todo.yml +1 -1
  35. package/engine/compositions/library/tool-web.yml +2 -2
  36. package/engine/compositions/source/local/code-presentation.yml +8 -0
  37. package/engine/compositions/source/local/context-gate.yml +0 -1
  38. package/engine/compositions/source/local/str-replace-editor.yml +10 -0
  39. package/engine/compositions/source/local/tool-bootstrap.yml +1 -3
  40. package/engine/compositions/source/local/tool-config-engine.yml +9 -0
  41. package/engine/compositions/source/local/tool-filter.yml +8 -0
  42. package/engine/cot-drip.mjs +137 -0
  43. package/engine/custom-bash.mjs +73 -21
  44. package/engine/deliberation-gate.mjs +127 -0
  45. package/engine/layers.mjs +223 -198
  46. package/engine/run-code-env.mjs +8 -2
  47. package/engine/schema.mjs +1 -1
  48. package/engine/strategies.mjs +25 -14
  49. package/engine/tool-bootstrap.mjs +185 -59
  50. package/engine/tool-config-engine.mjs +390 -0
  51. package/lib/client.js +3840 -2311
  52. package/lib/client.js.map +1 -1
  53. package/lib/index.d.mts +185 -79
  54. package/lib/index.mjs +1000 -356
  55. package/lib/preset-core.d.mts +1 -1
  56. package/lib/preset-core.mjs +29 -3
  57. package/lib/{prompt-configs-BgFw_bFf.mjs → prompt-configs-BnQKRHVb.mjs} +211 -136
  58. package/lib/prompt-configs-CN0sJTUL.d.mts +193 -0
  59. package/package.json +121 -105
  60. package/preset/anchored/preset.yml +262 -308
  61. package/preset/creative/preset.yml +34 -32
  62. package/preset/custom/preset.yml +0 -1
  63. package/preset/liangshen/preset.yml +53 -50
  64. package/preset/minimal/preset.yml +18 -17
  65. package/preset/ptc/preset.yml +35 -33
  66. package/preset/standard/preset.yml +34 -32
  67. package/templates/10-pre-step.yml +18 -15
  68. package/templates/14-first-turn-anchor.yml +13 -13
  69. package/templates/15-guide-auto.yml +13 -13
  70. package/templates/16-custom-fallback.yml +19 -18
  71. package/templates/18-placeholder-env-facts.yml +13 -2
  72. package/templates/30-runtime-context.yml +3 -0
  73. package/templates/40-agent-request.yml +9 -9
  74. package/templates/60-tool-pipeline.yml +9 -8
  75. package/templates/tools/10-shell-command.yml +20 -0
  76. package/templates/tools/20-http-fetch.yml +24 -0
  77. package/templates/tools/30-fs-read.yml +20 -0
  78. package/templates/tools/40-delegate-character.yml +15 -0
  79. package/templates/tools/50-delegate-worldbook.yml +15 -0
  80. package/templates/tools/60-delegate-session-var.yml +15 -0
  81. package/templates/tools/70-delegate-worldbook-upsert.yml +36 -0
  82. package/lib/prompt-configs-B4vH09wx.d.mts +0 -100
  83. package/templates/11-merged-a.yml +0 -11
  84. package/templates/13-anchor.yml +0 -19
  85. package/templates/17-instruction-hint.yml +0 -23
  86. package/templates/19-placeholder-skill-catalog.yml +0 -19
  87. package/templates/31-runtime-context-placeholder.yml +0 -18
package/README.md CHANGED
@@ -23,12 +23,13 @@ dsh --profile prompt-tool # 首次启
23
23
  - 🧑‍🤝‍🧑 **子代理三态**:`subagents: none / inherit / only`,身份类提示词可只注入子代理
24
24
  - 🗂️ **内容与执行分离**:每条提示词配置渲染为 `~/.dsh/.agent-presets/<预设>/prompt-configs/` 下的 yml,引擎按文件名数字前缀顺序扫描
25
25
  - 🧩 **三层合并**:引擎默认(按 params 生成)< 模板默认 promptConfigs < 预设 promptConfigs,同名 `id` 覆盖
26
- - 🖥️ **独立工作台**:侧边栏「提示词工具」入口(主会话/子代理/注入层/技能设置/预设配置五页)+ 设置面板提示词配置页(列表/表单/模板插入/保存前校验)
26
+ - 🖥️ **官方 slot 工作台**:`shell.overlay` 驱动的左上角悬浮按钮通过 body portal 落在对话界面层,右侧抽屉(主会话/子代理/技能设置/预设配置/角色管理五页)仍由官方 slot 承载;`settings.plugins.tab` 提供基础设置,`sidebar.footer.action` 几何探针跟随 264px 起步、可拉伸及 56px 折叠宽度,UI 挂载全部交给官方 SlotRegistry,无宿主 DOM 选择器
27
27
  - 🧪 **七种内容策略**:`static / first-turn-anchor / guide-auto / custom-fallback / instruction-hint / placeholder / world-book`(world-book 支持 ST selectiveLogic 选择性触发:任一/副键全中/排除)
28
28
  - 🛡️ **失败不伤会话**:单条失败跳过 + `warnOnce`;配置错误挂载时 fail loud;`dedupe: session` 持久幂等
29
29
  - 🎭 **SillyTavern 导入**:JSON 预设卡片一键转换为本地预设——`prompts[]` 映射提示词配置、setvar/getvar 收集进顶层 `variables`(未定义自定义宏自动登记空值占位)、`enable_web_search` 按开关装配工具;采样参数剥离(模型设置 UI 管理)
30
30
  - 🎴 **角色卡库**:SillyTavern 角色卡(PNG tEXt chunk `ccv3`/`chara`,或 chara_card JSON)导入独立库(`.characters/<id>/`,含原图/转换参数/角色记忆),按需「导入到当前预设」(`chara-<卡>-` 前缀合并、幂等可移除),多文件自动合并
31
- - 📚 **世界书**:`character_book` 转 world-book 策略配置(`keys` 命中触发 / `constant` 常驻 / `useRegex` 正则 / `selectiveLogic` 组合逻辑),与模块卡片同一存储与编辑(模块列表「世界书」过滤 + 批量启用/禁用)
31
+ - 📚 **世界书**:`character_book` 转 world-book 策略配置(`keys` 命中触发 / `constant` 常驻 / 正则键自动检测 / `selectiveLogic` 组合逻辑),与模块卡片同一存储与编辑(模块列表「世界书」过滤 + 批量启用/禁用)
32
+ - 🛠️ **自定义工具**:preset.yml `customTools` 段声明式定义模型工具(执行器 shell/http/delegate/fs/ask-user,`{{args.x}}` 参数插值),`tool-config-engine` 引擎行运行时注册;模块列表「自定义工具」卡片 JSON 编辑
32
33
  - 🧩 **模板变量**:预设级 `variables` 段(`{{key}}` 插值源)——模块列表顶部「模板变量」卡片统一编辑(可折叠/清空/停用/失焦自动保存);锚定匹配引擎(anchor-match)统一 custom-fallback 与 world-book 的匹配语义
33
34
  - 💬 **会话变量工具**:`session_var`(list/get/set/clear)——模型维护角色状态(`{{心情}}` 等),会话级覆盖预设默认;ST 运行时宏(`{{lastusermessage}}` / `{{lastcharmessage}}`)从会话事件提取
34
35
 
@@ -38,22 +39,23 @@ dsh --profile prompt-tool # 首次启
38
39
 
39
40
  | 层 | 职责 |
40
41
  |---|---|
41
- | `hostDefaults` | settings 层默认值(开关/路径),被用户 settings 覆盖 |
42
- | `params` | 引擎行为默认(锚定/引导/PTC/门控/模型/工具),被运行时 settings 覆盖 |
43
- | `moduleConfigs` | 引擎组合行级 config(persona 文本/超时/白名单) |
42
+ | `params` | 引擎行为参数(锚定/引导/PTC/门控/模型/工具),经参数桥落位组合行;UI 可管理,优先级最高 |
43
+ | `moduleConfigs` | 行级 config 直写通道(参数桥未覆盖的键:超时/环境白名单/ST 导入等),不锁定覆盖 UI 可管理参数 |
44
44
  | `promptConfigs` | 注入提示词配置(策略/层/位置/时机),与目录、settings 三源合并 |
45
45
 
46
46
  ### params 一览(全部可选,缺省 = 官方默认)
47
47
 
48
48
  | 分类 | 键 |
49
49
  |---|---|
50
- | 锚定 | `firstTurnAnchor` `firstTurnCustom` `firstTurnText` `firstTurnWord` `firstTurnBuild` `firstTurnInspect` `firstTurnDeep` |
51
- | 引导 | `guideCustom` `guideText` `guideComplexPattern` `guideWeak` `guideDeep` `buildPattern` `complexPattern` |
50
+ | 锚定 | `firstTurnAnchor` `firstTurnCustom` `firstTurnText` `firstTurnWord`(空 = 自动从锚句派生确认词)`firstTurnBuild` `firstTurnInspect` `firstTurnDeep` |
51
+ | 引导 | `guideCustom` `guideText` `guideWeak` `guideDeep`(复杂判定 fallback 复用锚定的 `complexPattern`) |
52
52
  | PTC/门控 | `usePtcMode` `bootstrapMaxTokens` `injectPrompt` `allowKinds` |
53
- | 人设 | 模块列表的 `persona-main`(system-section + `deployment:persona`,complete 互斥 + suppressRuntimeContext);`subagentPersona`(子代理显式,缺省经 scope 链继承主会话) |
53
+ | 人设 | 配置卡:主会话 = `persona-main` 卡(system-section + `deployment:persona`,complete 互斥 + suppressRuntimeContext);子代理独立人设 = 新建配置卡(system-section + `audience=subagent` + 人设段),装配时替换主会话人设(不继承);无子代理卡 = scope 链继承主会话 |
54
54
  | 工具集 | `toolFilterAllow` `toolFilterDeny`(子代理 toolFilter;主对话 tool-filter 模块共用) |
55
55
  | 深度 | `maxDepth`(0 禁止委派 / `provider-managed` / 正整数) |
56
56
 
57
+ > 注:`injectPrompt`(params)= 锚定确认后注入 preset.md 的开关;`injectAgentsPrompt`(settings)= 把 AGENTS.md 内容作为 instruction-hint 提示文本的开关。两者功能不同,勿混淆。
58
+
57
59
  模型参数在 **preset.yml 顶层 `model` / `subagentModel` 段**(官方 `agent-default-model` 同构):
58
60
 
59
61
  | 段 | 键 |
@@ -111,7 +113,7 @@ dsh --profile prompt-tool # 首次启
111
113
  `character_book` 条目转 world-book 策略配置(与普通模块同一存储/编辑):
112
114
 
113
115
  - **注入语义**:`constant` 常驻注入;有 `keys` 命中聊天内容才注入;无 keys 全局每次注入
114
- - **匹配选项**:`caseSensitive` / `wholeWords` / `useRegex`(keys 按正则)
116
+ - **匹配选项**:`caseSensitive` / `wholeWords`;正则形态键(`/regex/` 或含特殊字符)自动检测
115
117
  - **管理**:模块列表顶部下拉选「世界书」过滤(完整模块卡片编辑 + 批量启用/禁用);
116
118
  模型工具 `world_book_list/upsert/delete`(`note` 写入角色卡记忆)
117
119
  - **ST 变量**:`setvar`/`getvar` 收集进顶层 `variables`、未定义自定义宏自动登记空值占位;
@@ -12,8 +12,8 @@
12
12
  *
13
13
  * 模式:
14
14
  * scan = 全文扫描(world-book 消息批匹配);
15
- * prefix = 文本开头匹配(custom-fallback 首轮 reasoning 锚定确认:ASCII 词边界前缀,
16
- * ASCII 直 prefix)。
15
+ * prefix = 文本开头匹配(custom-fallback 首轮 reasoning 锚定确认:确认词集合任一
16
+ * 前缀命中——ASCII 词边界前缀,非 ASCII 直 prefix)。
17
17
  */
18
18
 
19
19
  /** 组合逻辑(ST world_info_logic 映射)。 */
@@ -29,13 +29,38 @@ export function escapeRegExp(text) {
29
29
  return String(text).replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
30
30
  }
31
31
 
32
- /** 单键正则编译(逐键匹配:any/all/not 需要精确的命中键数,捕获组会干扰 match 计数)。 */
32
+ /** ST 正则键检测(对齐 world-info.js parseRegexFromString):
33
+ * 仅 /pattern/flags 显式包裹的键按正则匹配,其余一律字面(含 {{user}} 等
34
+ * 含花括号/正则特殊字符的普通键——ST 不做特殊字符自动检测)。 */
35
+ export function isRegexKey(key) {
36
+ return parseRegexFromString(key) !== undefined
37
+ }
38
+
39
+ /** 键 → RegExp(仅 /pattern/flags 形态,模式内未转义 / 分隔符视为非法);否则 undefined。 */
40
+ export function parseRegexFromString(key) {
41
+ const m = /^\/([\s\S]+?)\/([gimsuy]*)$/u.exec(key)
42
+ if (m === null) return undefined
43
+ // ST 官方:模式内未转义的 / 分隔符非法(其它引擎无法解析该正则)。
44
+ if (/(^|[^\\])\//.test(m[1])) return undefined
45
+ try {
46
+ return new RegExp(m[1].replaceAll('\\/', '/'), m[2])
47
+ } catch {
48
+ return undefined
49
+ }
50
+ }
51
+
52
+ /** 单键正则编译(逐键匹配:any/all/not 需要精确的命中键数,捕获组会干扰 match 计数)。
53
+ * useRegex 三态:true=强制正则;false=强制字面;缺省=ST 语义自动检测。 */
33
54
  function compileSingle(key, { caseSensitive, wholeWords, useRegex }) {
34
55
  const flags = caseSensitive ? '' : 'i'
35
- if (useRegex) {
56
+ if (useRegex === true) {
36
57
  // ST use_regex=true:键原样作为正则(作者负责合法性)。
37
58
  return new RegExp(key, flags)
38
59
  }
60
+ if (useRegex === undefined) {
61
+ const auto = parseRegexFromString(key)
62
+ if (auto !== undefined) return auto
63
+ }
39
64
  if (wholeWords) {
40
65
  return new RegExp(`(^|[^\\p{L}\\p{N}])(${escapeRegExp(key)})(?![\\p{L}\\p{N}])`, `${flags}u`)
41
66
  }
@@ -57,7 +82,7 @@ function compileKeyList(list, options) {
57
82
  * @param {string[]} [options.secondaryKeys] 副键
58
83
  * @param {boolean} [options.caseSensitive]
59
84
  * @param {boolean} [options.wholeWords]
60
- * @param {boolean} [options.useRegex]
85
+ * @param {boolean} [options.useRegex] 三态:true=强制正则 / false=强制字面 / 缺省=自动检测(ST 语义)
61
86
  * @param {'any'|'all'|'not'|'notAny'} [options.logic] 组合逻辑(缺省 any)
62
87
  * @param {'scan'|'prefix'} [options.mode] 匹配模式(缺省 scan)
63
88
  * @returns {{ scan: (text: string) => { primary: number, secondary: number, active: boolean } }}
@@ -68,7 +93,7 @@ export function createAnchorMatcher(options = {}) {
68
93
  secondaryKeys = [],
69
94
  caseSensitive = false,
70
95
  wholeWords = false,
71
- useRegex = false,
96
+ useRegex = undefined,
72
97
  logic = MATCH_LOGIC.ANY,
73
98
  mode = 'scan',
74
99
  } = options
@@ -78,13 +103,14 @@ export function createAnchorMatcher(options = {}) {
78
103
  const scan = (raw) => {
79
104
  const text = String(raw ?? '')
80
105
  if (mode === 'prefix') {
81
- // custom-fallback 锚定确认:仅主键首词,文本开头匹配。
82
- const word = (Array.isArray(keys) ? keys : []).map((key) => String(key).trim())
83
- .find((key) => key.length > 0)
84
- if (word === undefined || text.length === 0) return { primary: 0, secondary: 0, active: false }
85
- const hit = /^[\x20-\x7E]+$/.test(word)
106
+ // custom-fallback 锚定确认:确认词集合任一前缀命中(any 语义——deep 档
107
+ // Let…/build We…/自定义锚句首词都可作为确认信号)。
108
+ const words = (Array.isArray(keys) ? keys : []).map((key) => String(key).trim())
109
+ .filter((key) => key.length > 0)
110
+ if (words.length === 0 || text.length === 0) return { primary: 0, secondary: 0, active: false }
111
+ const hit = words.some((word) => /^[\x20-\x7E]+$/.test(word)
86
112
  ? new RegExp(`^${escapeRegExp(word.toLowerCase())}\\b`, 'i').test(text)
87
- : text.startsWith(word)
113
+ : text.startsWith(word))
88
114
  return { primary: hit ? 1 : 0, secondary: 0, active: hit }
89
115
  }
90
116
  if (primaryList.length === 0 && secondaryList.length === 0) {
@@ -0,0 +1,68 @@
1
+ /**
2
+ * anchor-turn — 在用户首条真实消息之前播种一个合成锚定轮(前置锚定)。
3
+ *
4
+ * 移植自 upstream dsh-anchored-standard shared/anchor-turn.mjs (MIT):
5
+ * 锚定消息 PREPEND 进 `next-turn` inbox 队列、排在真实消息之前;dsh 每轮
6
+ * 只 claim 一条 next-turn 消息,所以首条模型请求 = 固定锚定提示(配合
7
+ * 零工具模式时 = 空工具面上的 "we" 锚定),用户真实消息由下一轮 claim——
8
+ * 彼时 bootstrap 已晋升、目录已开放。
9
+ *
10
+ * 与 near-anchor(first-turn-anchor 策略,消息级追加)正交:本模块是轮级
11
+ * 前置(真实消息延后一轮),near-anchor 是首条真实用户消息后的同轮追加。
12
+ *
13
+ * 在首条消息前(而非会话创建时)锚定,保持空白会话的预设切换器可用。
14
+ * 子代理默认跳过(其 brief 即计划);includeSubagents: true 让子代理也
15
+ * 走锚定轮。
16
+ *
17
+ * Durability 免费:prepend 经 `agent/inbox/spliced` 事件持久化,崩溃后
18
+ * 队列按序恢复;inbox replay 不触发 `inserted` 通知,锚定永不重注入。
19
+ *
20
+ * Robustness:插件来源消息(含自身锚定)永不再次锚定。
21
+ */
22
+
23
+ import { booleanOption, validateConfig } from './shared.mjs'
24
+
25
+ /** Cordis plugin name used by loader diagnostics. */
26
+ export const name = 'anchor-turn'
27
+
28
+ /** 默认锚定文本(合成首轮展示给模型)。 */
29
+ export const ANCHOR_TEXT = 'This round is a test. Tools are not open yet; all tools will open next round.'
30
+
31
+ /** Every config key this plugin accepts — anything else is a typo. */
32
+ const ALLOWED_KEYS = new Set(['enabled', 'text', 'includeSubagents'])
33
+
34
+ /** 全新会话(无任何历史 user/message)才锚定。 */
35
+ function isFreshSession(agent, includeSubagents = false) {
36
+ if (!includeSubagents && (agent.session.header.delegationDepth ?? 0) > 0) return false
37
+ return !agent.session.events.some((event) => event.type === 'user/message')
38
+ }
39
+
40
+ /** 注册首消息锚定注入。 */
41
+ export function apply(ctx, config) {
42
+ const source = validateConfig(name, config, ALLOWED_KEYS)
43
+ if (source.enabled === false) return
44
+ const text = typeof source.text === 'string' && source.text.length > 0
45
+ ? source.text
46
+ : ANCHOR_TEXT
47
+ const includeSubagents = booleanOption(name, source.includeSubagents, 'includeSubagents', false)
48
+
49
+ ctx.on('agent/inbox/inserted', ({ agent, message }) => {
50
+ if (agent?.session === undefined || agent?.inbox?.prepend === undefined) return
51
+ if (!isFreshSession(agent, includeSubagents)) return
52
+ // 插件来源消息(包括我们自己的锚定)永不再次锚定。
53
+ if (message?.source?.kind === 'plugin') return
54
+ agent.inbox.prepend('next-turn', {
55
+ id: typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'
56
+ ? crypto.randomUUID()
57
+ : `anchor-turn-${Date.now()}-${Math.random().toString(36).slice(2)}`,
58
+ role: 'user',
59
+ content: [{ type: 'text', text }],
60
+ source: {
61
+ kind: 'plugin',
62
+ plugin: name,
63
+ form: 'notice',
64
+ summary: 'zero-tool anchor turn',
65
+ },
66
+ })
67
+ })
68
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * classify-task — 任务分类器(能力归一)。
3
+ *
4
+ * buildPattern(构建任务正则)与 complexPattern(复杂任务正则)→ 三档分类
5
+ * (complex / build / fix)。锚定策略(first-turn-anchor)三档判定与引导策略
6
+ * (guide-auto)复杂判定共用本分类器——正则构建与判定逻辑单一实现,
7
+ * 避免两个策略各自 new RegExp + test(历史重复实现)。
8
+ *
9
+ * 参数缺省 = 对应分类不生效:buildRe/complexRe 未配置时跳过该分支
10
+ * (classify 落 fix;isComplex 恒 false)。
11
+ */
12
+ export function createTaskClassifier({ buildPattern, complexPattern }) {
13
+ const buildRe = typeof buildPattern === 'string' && buildPattern.length > 0
14
+ ? new RegExp(buildPattern, 'i')
15
+ : undefined
16
+ const complexRe = typeof complexPattern === 'string' && complexPattern.length > 0
17
+ ? new RegExp(complexPattern, 'i')
18
+ : undefined
19
+ return {
20
+ /** 锚定三档判定可用:两档正则都配置。 */
21
+ get ready() {
22
+ return buildRe !== undefined && complexRe !== undefined
23
+ },
24
+ /** 三档分类:complex > build > fix(fix 为兜底档)。 */
25
+ classify(text) {
26
+ if (complexRe !== undefined && complexRe.test(text)) return 'complex'
27
+ if (buildRe !== undefined && buildRe.test(text)) return 'build'
28
+ return 'fix'
29
+ },
30
+ /** 复杂判定(引导 fallback 用;正则未配置 = false)。 */
31
+ isComplex(text) {
32
+ return complexRe !== undefined && complexRe.test(text)
33
+ },
34
+ }
35
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * code-presentation - 晋升后 PTC mode wire 呈现。
3
+ *
4
+ * 从 tool-bootstrap 拆出的独立关注点:bootstrap 负责首轮工具目录窄化,
5
+ * 本模块只负责晋升后把工具呈现切换为 PTC mode(单 run_code,由
6
+ * tools.presentAs('ptc') 提供)。"只要 PTC 不要 bootstrap" = 组合只挂本行;
7
+ * PTC+bootstrap = 同时挂两行(行序:tool-bootstrap 在前,本行在后)。
8
+ *
9
+ * 相位与 tool-bootstrap / context-gate 同源:epoch-aware promotion
10
+ * (compaction-epoch.mjs)。晋升后(tool/call 或 assistant/message,按
11
+ * promoteOn,默认 either)应用 PTC mode;compaction/end 释放(压缩后回到
12
+ * 受控相位,重新晋升再应用)。
13
+ *
14
+ * SUBAGENTS: includeSubagents=false(默认)时子代理(delegationDepth > 0)
15
+ * 首次请求即应用呈现(继承完整目录语义);true 时子代理跟随主会话相位。
16
+ *
17
+ * Robustness: 应用/释放失败降级(绝不 brick 会话);invalid config fail at
18
+ * apply time,即 preset 挂载处可见可修。
19
+ */
20
+
21
+ import { createEpochPromotion } from './compaction-epoch.mjs'
22
+ import { booleanOption, parsePromoteOn, validateConfig } from './shared.mjs'
23
+
24
+ /** Cordis plugin name used by loader diagnostics. */
25
+ export const name = 'code-presentation'
26
+
27
+ /** 无 inject:监听器只在使用时触碰 ctx 服务(同 tool-bootstrap 纪律)。 */
28
+ export const inject = []
29
+
30
+ /** Every config key this plugin accepts — anything else is a typo. */
31
+ const ALLOWED_KEYS = new Set(['usePtcMode', 'includeSubagents', 'promoteOn'])
32
+
33
+ /** Register the post-promotion Code Mode presentation. */
34
+ export function apply(ctx, config) {
35
+ const source = validateConfig(name, config, ALLOWED_KEYS)
36
+ // 默认 false:PTC mode 呈现是 opt-in,未声明 = 原生完整工具目录。
37
+ const usePtcMode = booleanOption(name, source.usePtcMode, 'usePtcMode', false)
38
+ if (!usePtcMode) return
39
+ const includeSubagents = booleanOption(name, source.includeSubagents, 'includeSubagents', false)
40
+ const promoteEvents = parsePromoteOn(name, source.promoteOn)
41
+ const promotion = createEpochPromotion(promoteEvents, { includeSubagents })
42
+
43
+ const presentationBySession = new WeakMap()
44
+ const agentBySession = new WeakMap()
45
+ const presentationState = (session) => {
46
+ let state = presentationBySession.get(session)
47
+ if (state === undefined) {
48
+ state = { applied: false, disposer: undefined }
49
+ presentationBySession.set(session, state)
50
+ }
51
+ return state
52
+ }
53
+ const applyCodePresentation = (agent) => {
54
+ const session = agent?.session
55
+ if (session === undefined) return
56
+ const state = presentationState(session)
57
+ if (state.applied) return
58
+ const tools = agent.ctx?.tools
59
+ if (tools === undefined || typeof tools.presentAs !== 'function') return
60
+ state.disposer = tools.presentAs('ptc')
61
+ state.applied = true
62
+ }
63
+ const releaseCodePresentation = (session) => {
64
+ const state = presentationBySession.get(session)
65
+ if (state === undefined) return
66
+ if (typeof state.disposer === 'function') {
67
+ try { state.disposer() } catch { /* never brick the session */ }
68
+ }
69
+ state.disposer = undefined
70
+ state.applied = false
71
+ }
72
+
73
+ ctx.on('session/event', (session, event) => promotion.observe(session, event))
74
+ ctx.on('session/event', (session, event) => {
75
+ if (event.type === 'compaction/end') {
76
+ releaseCodePresentation(session)
77
+ return
78
+ }
79
+ if (event.type !== 'step/end' && event.type !== 'turn/end') return
80
+ const agent = agentBySession.get(session)
81
+ if (agent !== undefined && promotion.status(agent).promoted) applyCodePresentation(agent)
82
+ })
83
+
84
+ ctx.on('system-prompt/assemble', async (_assembly, context, next) => {
85
+ // Downstream errors propagate untouched; only this filter's own logic is guarded.
86
+ const assembled = await next()
87
+ try {
88
+ const agent = context.agent
89
+ if (agent === undefined || agent.session === undefined) return assembled
90
+ agentBySession.set(agent.session, agent)
91
+ if ((agent.session?.header?.delegationDepth ?? 0) > 0 && !includeSubagents) {
92
+ // 默认:子代理继承完整目录 → 直接应用呈现。
93
+ applyCodePresentation(agent)
94
+ return assembled
95
+ }
96
+ if (promotion.status(agent).promoted) applyCodePresentation(agent)
97
+ return assembled
98
+ } catch {
99
+ // 呈现失败不阻断会话:保持原样。
100
+ return assembled
101
+ }
102
+ })
103
+ }
@@ -0,0 +1,10 @@
1
+ # module: anchor-turn
2
+ # source: engine/compositions/library/anchor-turn.yml (本地附加,上游 dsh-anchored-standard 移植)
3
+ # 前置锚定轮:用户首条真实消息前 prepend 合成锚定轮(配合 zero-tool 模式 =
4
+ # 空工具面上的 "we" 锚定)。默认 enabled: false(挂载即禁用,行为不变);
5
+ # 启用 = params.anchorTurn(UI 开关)或本行 config.enabled: true。
6
+
7
+ - id: anchor-turn
8
+ name: ./engine/anchor-turn.mjs
9
+ config:
10
+ enabled: false
@@ -1,5 +1,5 @@
1
1
  # module: bootstrap-filesystem
2
- # source: E:\Documents\GitHub\deepseek-harness/apps/cli/config/agent-presets/minimal/agent.cordis.yml
2
+ # source: D:\AI\GitHub\deepseek-harness/packages/preset/agent-presets/presets/minimal/agent.cordis.yml
3
3
  # local patches: 1
4
4
 
5
5
  - id: bootstrap-filesystem
@@ -0,0 +1,8 @@
1
+ # module: code-presentation
2
+ # source: engine/compositions/source/local/code-presentation.yml (本地附加,非官方模块)
3
+ # 晋升后 Code Mode (PTC) wire 呈现(从 tool-bootstrap 拆出,与目录窄化解耦):
4
+ # "只要 PTC 不要 bootstrap" = modules 只挂本行;PTC+bootstrap = 同时挂两行。
5
+ # usePtcMode 默认 false(opt-in);params.usePtcMode 显式覆盖(参数桥)。
6
+
7
+ - id: code-presentation
8
+ name: ./engine/code-presentation.mjs
@@ -0,0 +1,11 @@
1
+ # module: command-goal
2
+ # source: D:\AI\GitHub\deepseek-harness/packages/preset/agent-presets/presets/standard/agent.cordis.yml
3
+ # local patches: 0
4
+
5
+ # ── goals ───────────────────────────────────────────────────────────────────
6
+
7
+ # The goal service and session driver stay on the host plane, where the Gateway
8
+ # can resolve them. The human command and model-facing tool register into this
9
+ # preset's scoped layers.
10
+ - id: command-goal
11
+ name: '@deepseek-ai/dsh-command-goal'
@@ -1,5 +1,5 @@
1
1
  # module: compaction
2
- # source: E:\Documents\GitHub\deepseek-harness/apps/cli/config/agent-presets/standard/agent.cordis.yml
2
+ # source: D:\AI\GitHub\deepseek-harness/packages/preset/agent-presets/presets/standard/agent.cordis.yml
3
3
  # local patches: 0
4
4
 
5
5
  # ── compaction ──────────────────────────────────────────────────────────────
@@ -1,12 +1,11 @@
1
1
  # module: context-gate
2
- # source: preset/engine/compositions/source/local/context-gate.yml (本地附加,非官方模块)
2
+ # source: engine/compositions/source/local/context-gate.yml (本地附加,非官方模块)
3
3
 
4
4
  - id: context-gate
5
5
  name: ./engine/context-gate.mjs
6
6
  config:
7
7
  promoteOn: either
8
8
  includeSubagents: false
9
- allowKinds: __allowKinds__
10
9
 
11
10
  # ── bootstrap ───────────────────────────────────────────────────────────────
12
11
 
@@ -0,0 +1,11 @@
1
+ # module: cot-drip
2
+ # source: engine/compositions/library/cot-drip.yml (本地附加,上游 dsh-anchored-standard 移植)
3
+ # 深思维持节拍:每 N 次工具结果滴入一条 "We …" 重申提醒(additionalContexts)。
4
+ # 默认 enabled: false(挂载即禁用);启用 = params.cotDrip(UI 开关)。
5
+
6
+ - id: cot-drip
7
+ name: ./engine/cot-drip.mjs
8
+ config:
9
+ enabled: false
10
+ every: 4
11
+ maxPerTurn: 1
@@ -1,5 +1,5 @@
1
1
  # module: custom-bash
2
- # source: preset/engine/compositions/source/local/custom-bash.yml (本地附加,非官方模块)
2
+ # source: engine/compositions/source/local/custom-bash.yml (本地附加,非官方模块)
3
3
 
4
4
  - id: custom-bash
5
5
  name: ./engine/custom-bash.mjs
@@ -1,6 +1,6 @@
1
1
  # module: delegation
2
- # source: E:\Documents\GitHub\deepseek-harness/apps/cli/config/agent-presets/standard/agent.cordis.yml
3
- # local patches: 2(SUBAGENT-CONFIG token ×2:子代理完整配置(模型/人设/工具集/深度),随预设参数渲染)
2
+ # source: D:\AI\GitHub\deepseek-harness/packages/preset/agent-presets/presets/standard/agent.cordis.yml
3
+ # local patches: 0
4
4
 
5
5
  # ── delegation and workflows ────────────────────────────────────────────────
6
6
 
@@ -36,20 +36,24 @@
36
36
  config:
37
37
  provider: spawn
38
38
  toolName: subagent
39
+ modelSelectionSettings: true
39
40
  backgroundMode: continuable
40
- __subagentConfig__
41
41
 
42
+ # Fork omits model selection so provider/model stay equal to the parent and
43
+ # the inherited history remains eligible for KV Cache reuse. This preset
44
+ # keeps fork continuable and accepts its child-scoped `report` additions invalidating
45
+ # that prefix; issue #2124 tracks cache-preserving continuable fork.
42
46
  - id: tool-subagent-fork
43
47
  name: '@deepseek-ai/dsh-tool-subagent'
44
48
  config:
45
49
  provider: fork
46
50
  toolName: subagent_fork
47
51
  backgroundMode: continuable
48
- __subagentConfig__
49
52
 
50
- # Production dsh does not install these optional providers. An opting-in
51
- # Profile mounts each provider once on the host plane; copy this preset,
52
- # then remove `disabled` from the matching tool row.
53
+ # Production dsh does not install these optional providers. Install the
54
+ # matching Bundle in this Profile and restart the Host, then copy this
55
+ # preset and remove `disabled` from the matching tool row. Host availability
56
+ # alone grants no tool.
53
57
  - id: tool-subagent-codex
54
58
  name: '@deepseek-ai/dsh-tool-subagent'
55
59
  disabled: true
@@ -0,0 +1,11 @@
1
+ # module: deliberation-gate
2
+ # source: engine/compositions/library/deliberation-gate.yml (本地附加,上游 dsh-anchored-standard 移植)
3
+ # 轨迹深度门:首工具调用前流式深思 < minChars 时 deny 一次(规划式提示)。
4
+ # 默认 enabled: false(挂载即禁用);启用 = params.deliberationGate(UI 开关)。
5
+
6
+ - id: deliberation-gate
7
+ name: ./engine/deliberation-gate.mjs
8
+ config:
9
+ enabled: false
10
+ minChars: 400
11
+ maxGatesPerTurn: 1
@@ -1,5 +1,5 @@
1
1
  # module: persistent-shell
2
- # source: E:\Documents\GitHub\deepseek-harness/apps/cli/config/agent-presets/minimal/agent.cordis.yml
2
+ # source: D:\AI\GitHub\deepseek-harness/packages/preset/agent-presets/presets/minimal/agent.cordis.yml
3
3
  # local patches: 2
4
4
 
5
5
  - id: persistent-shell
@@ -14,12 +14,14 @@
14
14
 
15
15
  - id: terminal-bash
16
16
  name: '@deepseek-ai/dsh-terminal-bash'
17
+ disabled: !!js process.platform === 'win32'
17
18
  config:
18
19
  shellPath: !!js "process.getBuiltinModule?.('node:fs')?.existsSync('/bin/bash') ? '/bin/bash' : 'bash'"
19
20
  timeoutMs: 300000
20
21
 
21
22
  - id: persistent-bash
22
23
  name: '@deepseek-ai/dsh-tool-bash-persistent'
24
+ disabled: !!js process.platform === 'win32'
23
25
  config:
24
26
  timeoutMs: 300000
25
27
  description: |-
@@ -32,5 +34,26 @@
32
34
  * Please avoid commands that may produce a very large amount of output.
33
35
  * Please run long lived commands in the background, e.g. 'sleep 10 &' or start a server in the background.
34
36
 
37
+ - id: terminal-pwsh
38
+ name: '@deepseek-ai/dsh-terminal-bash'
39
+ disabled: !!js process.platform !== 'win32'
40
+ config:
41
+ shellDialect: pwsh
42
+ timeoutMs: 300000
43
+
44
+ - id: persistent-pwsh
45
+ name: '@deepseek-ai/dsh-tool-pwsh-persistent'
46
+ disabled: !!js process.platform !== 'win32'
47
+ config:
48
+ timeoutMs: 300000
49
+ description: |-
50
+ Run commands in a PowerShell shell
51
+ * When invoking this tool, the contents of the "command" parameter does NOT need to be XML-escaped.
52
+ * You don't have access to the internet via this tool.
53
+ * State is persistent across command calls and discussions with the user.
54
+ * Use native Windows paths (C:\...) and $env:NAME variables; this is PowerShell, not bash.
55
+ * Please avoid commands that may produce a very large amount of output.
56
+ * Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.
57
+
35
58
  # The bare local filesystem shadows the host's sandboxed provider only for this
36
- # preset. The editor shares that realm and requires absolute paths.
59
+ # preset. The editor shares that realm and requires absolute paths.
@@ -1,7 +1,11 @@
1
1
  # module: persona
2
- # source: deepseek-harness official standard agent preset (persona)
3
- # persona 差异(creative/minimal/anchored)由 preset.yml moduleConfigs 参数传递。
2
+ # source: D:\AI\GitHub\deepseek-harness/packages/preset/agent-presets/presets/standard/agent.cordis.yml
3
+ # local patches: 0
4
4
 
5
+ # ── identity ────────────────────────────────────────────────────────────────
6
+
7
+ # The preset's own persona, shadowing the deployment default for this agent.
8
+ # `{{model}}` and `{{cwd}}` resolve from the agent's own route and workspace.
5
9
  - id: persona
6
10
  name: '@deepseek-ai/dsh-persona'
7
11
  config:
@@ -1,5 +1,5 @@
1
1
  # module: planning
2
- # source: E:\Documents\GitHub\deepseek-harness/apps/cli/config/agent-presets/standard/agent.cordis.yml
2
+ # source: D:\AI\GitHub\deepseek-harness/packages/preset/agent-presets/presets/standard/agent.cordis.yml
3
3
  # local patches: 0
4
4
 
5
5
  # ── plan mode ───────────────────────────────────────────────────────────────
@@ -1,5 +1,5 @@
1
1
  # module: prompt-config-engine
2
- # source: preset/engine/compositions/source/local/prompt-config-engine.yml (本地附加,非官方模块)
2
+ # source: engine/compositions/source/local/prompt-config-engine.yml (本地附加,非官方模块)
3
3
 
4
4
  - id: prompt-config-engine
5
5
  name: ./engine/prompt-config-engine.mjs
@@ -1,5 +1,5 @@
1
1
  # module: run-code-env
2
- # source: preset/engine/compositions/source/local/run-code-env.yml (本地附加,非官方模块)
2
+ # source: engine/compositions/source/local/run-code-env.yml (本地附加,非官方模块)
3
3
 
4
4
  - id: run-code-env
5
5
  name: ./engine/run-code-env.mjs
@@ -1,5 +1,5 @@
1
1
  # module: skill-filesystem
2
- # source: E:\Documents\GitHub\deepseek-harness/apps/cli/config/agent-presets/standard/agent.cordis.yml
2
+ # source: D:\AI\GitHub\deepseek-harness/packages/preset/agent-presets/presets/standard/agent.cordis.yml
3
3
  # local patches: 0
4
4
 
5
5
  # ── skills ──────────────────────────────────────────────────────────────────
@@ -1,5 +1,5 @@
1
1
  # module: skill-search
2
- # source: preset/engine/compositions/source/local/skill-search.yml (本地附加,非官方模块)
2
+ # source: engine/compositions/source/local/skill-search.yml (本地附加,非官方模块)
3
3
 
4
4
  - id: skill-search
5
5
  name: ./engine/skill-search.mjs
@@ -1,5 +1,5 @@
1
1
  # module: str-replace-editor
2
- # source: E:\Documents\GitHub\deepseek-harness/apps/cli/config/agent-presets/minimal/agent.cordis.yml
2
+ # source: engine/compositions/source/local/str-replace-editor.yml (本地附加,非官方模块)
3
3
  # 官方 minimal 内置工具(filesystem group 内的 str-replace-editor 行)拆出为独立模块:
4
4
  # 复用宿主 sandbox 的 ctx.fs,不挂 fs-local 裸文件系统。
5
5
  # maxOutputChars 参数化:params.strReplaceEditorMaxOutputChars(默认官方值 16000)。
@@ -7,4 +7,4 @@
7
7
  - id: str-replace-editor
8
8
  name: '@deepseek-ai/dsh-tool-str-replace-editor'
9
9
  config:
10
- maxOutputChars: __strReplaceEditorMaxOutputChars__
10
+ maxOutputChars: 16000
@@ -1,5 +1,5 @@
1
1
  # module: tool-ask-user
2
- # source: E:\Documents\GitHub\deepseek-harness/apps/cli/config/agent-presets/standard/agent.cordis.yml
2
+ # source: D:\AI\GitHub\deepseek-harness/packages/preset/agent-presets/presets/standard/agent.cordis.yml
3
3
  # local patches: 0
4
4
 
5
5
  # ── remaining model-facing rows ─────────────────────────────────────────────
@@ -1,5 +1,5 @@
1
1
  # module: tool-bash
2
- # source: E:\Documents\GitHub\deepseek-harness/apps/cli/config/agent-presets/standard/agent.cordis.yml
2
+ # source: D:\AI\GitHub\deepseek-harness/packages/preset/agent-presets/presets/standard/agent.cordis.yml
3
3
  # local patches: 1
4
4
 
5
5
  # ── shell ───────────────────────────────────────────────────────────────────