dsh-plugin-prompt-tool 0.5.0 → 0.6.1

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 (38) hide show
  1. package/README.md +18 -12
  2. package/engine/anchor-match.mjs +117 -0
  3. package/engine/compositions/library/context-gate.yml +2 -2
  4. package/engine/compositions/library/delegation.yml +2 -2
  5. package/engine/compositions/library/str-replace-editor.yml +1 -1
  6. package/engine/compositions/library/tool-bootstrap.yml +2 -2
  7. package/engine/compositions/library/tool-filter.yml +3 -3
  8. package/engine/compositions/source/local/context-gate.yml +2 -2
  9. package/engine/compositions/source/local/tool-bootstrap.yml +3 -3
  10. package/engine/executor.mjs +9 -2
  11. package/engine/interpolate.mjs +116 -0
  12. package/engine/layers.mjs +26 -22
  13. package/engine/schema.mjs +18 -0
  14. package/engine/session-vars.mjs +52 -0
  15. package/engine/shared.mjs +0 -19
  16. package/engine/strategies.mjs +28 -38
  17. package/lib/client.js +471 -162
  18. package/lib/client.js.map +1 -1
  19. package/lib/index.d.mts +35 -9
  20. package/lib/index.mjs +376 -92
  21. package/lib/preset-core.d.mts +2 -2
  22. package/lib/preset-core.mjs +3 -6
  23. package/lib/{prompt-configs-BcP6miu9.d.mts → prompt-configs-B4vH09wx.d.mts} +1 -3
  24. package/lib/{prompt-configs-k7wuZs0C.mjs → prompt-configs-ThS4iXPg.mjs} +85 -33
  25. package/package.json +105 -104
  26. package/preset/anchored/preset.yml +40 -42
  27. package/preset/creative/preset.yml +33 -30
  28. package/preset/creative/skills/cordis-plugin-development/SKILL.md +420 -0
  29. package/preset/creative/skills/editing-cordis-compositions/SKILL.md +165 -0
  30. package/preset/liangshen/preset.yml +24 -18
  31. package/preset/minimal/preset.yml +27 -24
  32. package/preset/ptc/preset.yml +23 -17
  33. package/preset/standard/preset.yml +23 -17
  34. package/templates/20-system-section.yml +5 -0
  35. package/templates/70-subagent-maintenance.yml +38 -0
  36. package/engine/compositions/library/router-first-turn.yml +0 -9
  37. package/engine/compositions/source/local/router-first-turn.yml +0 -5
  38. package/engine/router-first-turn.mjs +0 -85
@@ -6,15 +6,11 @@
6
6
  */
7
7
 
8
8
  import { extractText } from './shared.mjs'
9
+ import { MATCH_LOGIC, createAnchorMatcher } from './anchor-match.mjs'
9
10
  import { createInstructionHintResolver, createPlaceholderResolver } from './fillers.mjs'
10
11
 
11
12
  const name = 'prompt-config-engine'
12
13
 
13
- /** 锚定词正则转义。 */
14
- function escapeRegExp(text) {
15
- return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
16
- }
17
-
18
14
  /**
19
15
  * first-turn-anchor:首条真实用户消息后的一次性任务锚点。
20
16
  * 正则与锚句文本全部来自 config.params(由 preset.yml 单一配置源下发)。
@@ -74,16 +70,6 @@ function createGuideAutoResolver(config) {
74
70
  }
75
71
  }
76
72
 
77
- /** 判断 reasoning 开头是否命中自定义锚定词:ASCII 词按词边界匹配,其他按前缀匹配。 */
78
- function matchesAnchorWord(raw, firstTurnWord) {
79
- const text = String(raw ?? '').trim()
80
- if (text.length === 0 || firstTurnWord.length === 0) return false
81
- if (/^[\x20-\x7E]+$/.test(firstTurnWord)) {
82
- return new RegExp(`^${escapeRegExp(firstTurnWord.toLowerCase())}\\b`, 'i').test(text)
83
- }
84
- return text.startsWith(firstTurnWord)
85
- }
86
-
87
73
  /**
88
74
  * custom-fallback:自定义锚定词命中后注入一次,未命中最多两轮兜底。
89
75
  * 参数全部来自 config.params(由 preset.yml 单一配置源下发)。
@@ -95,6 +81,8 @@ function createCustomFallbackResolver(config) {
95
81
  const firstTurnWord = typeof config.params?.firstTurnWord === 'string' && config.params.firstTurnWord.length > 0
96
82
  ? config.params.firstTurnWord
97
83
  : 'we'
84
+ // 锚定匹配经 anchor-match 引擎(prefix 模式:首轮 reasoning 开头命中锚定词)。
85
+ const anchor = createAnchorMatcher({ keys: [firstTurnWord], mode: 'prefix' })
98
86
 
99
87
  const anchorScanned = new Map()
100
88
 
@@ -106,7 +94,7 @@ function createCustomFallbackResolver(config) {
106
94
  if (first === undefined) return false
107
95
  const content = first.data?.message?.content ?? []
108
96
  const reasoning = content.find((block) => block.type === 'reasoning')
109
- const confirmed = reasoning !== undefined && matchesAnchorWord(reasoning.text, firstTurnWord)
97
+ const confirmed = reasoning !== undefined && anchor.scan(String(reasoning.text ?? '')).active
110
98
  anchorScanned.set(session.id, confirmed)
111
99
  return confirmed
112
100
  }
@@ -135,41 +123,43 @@ function createCustomFallbackResolver(config) {
135
123
 
136
124
  /**
137
125
  * world-book:世界书条目(角色卡 lorebook)。constant=true 恒注入(不扫 keys);
138
- * selective 条目扫描当前消息批文本,keys/secondaryKeys 任一命中即注入。
139
- * 大小写/整词匹配可配(caseSensitive / wholeWords);未命中返回 null(不注入)。
126
+ * selective 条目扫描当前消息批文本,keys/secondaryKeys 按 selectiveLogic 组合
127
+ * (any=任一命中 / all=副键全中 / not=副键全不中)。匹配经 anchor-match 引擎。
140
128
  */
141
129
  function createWorldBookResolver(config) {
142
130
  const constant = config.params?.constant === true
143
- const caseSensitive = config.params?.caseSensitive === true
144
- const wholeWords = config.params?.wholeWords === true
145
- const useRegex = config.params?.useRegex === true
146
- const rawKeys = Array.isArray(config.params?.keys) ? config.params.keys : []
147
- const rawSecondary = Array.isArray(config.params?.secondaryKeys) ? config.params.secondaryKeys : []
148
- const keys = [...rawKeys, ...rawSecondary]
149
- .map((key) => String(key).trim())
150
- .filter((key) => key.length > 0)
151
- const needle = keys.length > 0
152
- ? (useRegex
153
- // ST use_regex=true:keys 为正则表达式(原样拼接,模型提示词作者负责合法性)。
154
- ? new RegExp(keys.join('|'), caseSensitive ? '' : 'i')
155
- : (wholeWords
156
- ? new RegExp(`(^|[^\\p{L}\\p{N}])(${keys.map((key) => escapeRegExp(key)).join('|')})(?![\\p{L}\\p{N}])`, `${caseSensitive ? '' : 'i'}u`)
157
- : new RegExp(keys.map((key) => escapeRegExp(key)).join('|'), caseSensitive ? '' : 'i'))
158
- )
159
- : undefined
131
+ // selectiveLogic:ST world_info_logic 0=AND_ANY 1=NOT_ALL 2=NOT_ANY 3=AND_ALL。
132
+ const rawLogic = config.params?.selectiveLogic
133
+ const logic = rawLogic === 3
134
+ ? MATCH_LOGIC.ALL
135
+ : (rawLogic === 1
136
+ ? MATCH_LOGIC.NOT
137
+ : (rawLogic === 2 ? MATCH_LOGIC.NOT_ANY : MATCH_LOGIC.ANY))
138
+ const matcher = createAnchorMatcher({
139
+ keys: Array.isArray(config.params?.keys) ? config.params.keys : [],
140
+ secondaryKeys: Array.isArray(config.params?.secondaryKeys) ? config.params.secondaryKeys : [],
141
+ caseSensitive: config.params?.caseSensitive === true,
142
+ wholeWords: config.params?.wholeWords === true,
143
+ useRegex: config.params?.useRegex === true,
144
+ logic,
145
+ })
146
+ // ST 语义:constant 或无任何键的条目恒注入(always active)。
147
+ const hasAnyKey = (Array.isArray(config.params?.keys) ? config.params.keys : [])
148
+ .some((key) => String(key).trim().length > 0)
149
+ || (Array.isArray(config.params?.secondaryKeys) ? config.params.secondaryKeys : [])
150
+ .some((key) => String(key).trim().length > 0)
160
151
  const promptText = config.texts.length > 0
161
152
  ? config.texts.join('\n\n')
162
153
  : (typeof config.params?.text === 'string' && config.params.text.length > 0 ? config.params.text : undefined)
163
154
  return ({ messages }) => {
164
155
  if (promptText === undefined) return null
165
- if (constant || needle === undefined) return { text: promptText }
156
+ if (constant || !hasAnyKey) return { text: promptText }
166
157
  const haystack = (Array.isArray(messages) ? messages : [])
167
158
  .map((message) => extractText(message))
168
159
  .filter((text) => text.length > 0)
169
160
  .join('\n')
170
161
  if (haystack.length === 0) return null
171
- needle.lastIndex = 0
172
- return needle.test(haystack) ? { text: promptText } : null
162
+ return matcher.scan(haystack).active ? { text: promptText } : null
173
163
  }
174
164
  }
175
165