dsh-plugin-prompt-tool 0.8.1 → 2.0.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 (139) hide show
  1. package/README.md +84 -67
  2. package/engine/actions/append-context.mjs +49 -0
  3. package/engine/actions/assembly.mjs +150 -0
  4. package/engine/actions/catalog.mjs +92 -0
  5. package/engine/actions/content.mjs +205 -0
  6. package/engine/actions/decision.mjs +54 -0
  7. package/engine/actions/examples.mjs +11 -0
  8. package/engine/actions/guard.mjs +80 -0
  9. package/engine/actions/inbox-prepend.mjs +37 -0
  10. package/engine/actions/index.mjs +100 -0
  11. package/engine/actions/inject-text.mjs +22 -0
  12. package/engine/actions/pre-step-filter.mjs +55 -0
  13. package/engine/actions/registration.mjs +168 -0
  14. package/engine/actions/request-params.mjs +32 -0
  15. package/engine/actions/sdk-strip.mjs +30 -0
  16. package/engine/actions/shared.mjs +71 -0
  17. package/engine/actions.mjs +2 -931
  18. package/engine/branch.mjs +44 -0
  19. package/engine/character-tools.mjs +3 -6
  20. package/engine/compaction-epoch.mjs +31 -13
  21. package/engine/compositions/library/agent-instructions.yml +1 -1
  22. package/engine/compositions/library/command-goal.yml +1 -1
  23. package/engine/compositions/library/compaction.yml +1 -1
  24. package/engine/compositions/library/delegation-ptc.yml +1 -1
  25. package/engine/compositions/library/delegation.yml +1 -1
  26. package/engine/compositions/library/persistent-shell.yml +1 -1
  27. package/engine/compositions/library/planning.yml +1 -1
  28. package/engine/compositions/library/skill-filesystem-cordis.yml +1 -1
  29. package/engine/compositions/library/skill-filesystem.yml +1 -1
  30. package/engine/compositions/library/tool-ask-user.yml +1 -1
  31. package/engine/compositions/library/tool-bash.yml +1 -1
  32. package/engine/compositions/library/tool-cordis.yml +1 -1
  33. package/engine/compositions/library/tool-fs-search.yml +1 -1
  34. package/engine/compositions/library/tool-fs.yml +1 -1
  35. package/engine/compositions/library/tool-goal.yml +1 -1
  36. package/engine/compositions/library/tool-jobs.yml +1 -1
  37. package/engine/compositions/library/tool-plugin-manager-disabled.yml +1 -1
  38. package/engine/compositions/library/tool-plugin-manager.yml +1 -1
  39. package/engine/compositions/library/tool-present.yml +1 -1
  40. package/engine/compositions/library/tool-presentation.yml +1 -1
  41. package/engine/compositions/library/tool-pwsh.yml +1 -1
  42. package/engine/compositions/library/tool-skill.yml +1 -1
  43. package/engine/compositions/library/tool-todo.yml +1 -1
  44. package/engine/compositions/library/tool-web.yml +1 -1
  45. package/engine/compositions/source/local/dev-tool-search.yml +11 -0
  46. package/engine/compositions/source/local/instruction-hint.yml +22 -1
  47. package/engine/compositions/source/local/rule-engine.yml +6 -0
  48. package/engine/condition.mjs +16 -3
  49. package/engine/conditions/anchor.mjs +32 -0
  50. package/engine/conditions/availability.mjs +47 -0
  51. package/engine/conditions/composite.mjs +83 -0
  52. package/engine/conditions/count.mjs +140 -0
  53. package/engine/conditions/evaluation.mjs +41 -0
  54. package/engine/conditions/examples.mjs +11 -0
  55. package/engine/conditions/index.mjs +85 -0
  56. package/engine/conditions/names.mjs +21 -0
  57. package/engine/conditions/phase.mjs +54 -0
  58. package/engine/conditions/preset.mjs +94 -0
  59. package/engine/conditions/scope.mjs +18 -0
  60. package/engine/conditions/session.mjs +22 -0
  61. package/engine/conditions/source.mjs +63 -0
  62. package/engine/conditions/subject.mjs +121 -0
  63. package/engine/conditions/text.mjs +44 -0
  64. package/engine/conditions/values.mjs +32 -0
  65. package/engine/dev-tool-search.mjs +213 -0
  66. package/engine/executor.mjs +93 -31
  67. package/engine/fillers.mjs +23 -16
  68. package/engine/instruction-hint.mjs +39 -23
  69. package/engine/layers.mjs +171 -77
  70. package/engine/order.mjs +20 -0
  71. package/engine/predicates.mjs +2 -753
  72. package/engine/rule-engine.mjs +40 -0
  73. package/engine/rule-runtime.mjs +110 -0
  74. package/engine/rule-spec.mjs +187 -0
  75. package/engine/schema.mjs +32 -11
  76. package/engine/session-var-tools.mjs +3 -6
  77. package/engine/shared.mjs +1 -1
  78. package/engine/st-render.mjs +8 -4
  79. package/engine/strategies.mjs +2 -235
  80. package/engine/subagent-tool-policy-core.mjs +7 -7
  81. package/engine/subagent-tool-policy.mjs +45 -20
  82. package/engine/tool-config-engine.mjs +53 -32
  83. package/engine/trigger-editor-meta.mjs +2 -21
  84. package/engine/trigger-spec.mjs +49 -133
  85. package/engine/world-book-tools.mjs +3 -6
  86. package/lib/client.js +10444 -10886
  87. package/lib/client.js.map +1 -1
  88. package/lib/index.d.mts +265 -361
  89. package/lib/index.mjs +1559 -2026
  90. package/lib/migrate-rules.d.mts +1 -0
  91. package/lib/migrate-rules.mjs +39 -0
  92. package/lib/module-package-CHPFweqK.mjs +2 -0
  93. package/lib/module-package-Cnd1_mwx.mjs +2872 -0
  94. package/lib/{paths-CY5psBqE.d.mts → paths-CyP0IkaM.d.mts} +388 -231
  95. package/lib/preset-transfer.d.mts +2 -2
  96. package/lib/preset-transfer.mjs +3 -2
  97. package/lib/{preset-package-BnJqrU4R.mjs → rules-migration-DJ6vASB5.mjs} +13825 -15283
  98. package/modules/ponytail/module.yml +406 -0
  99. package/modules/skill-surface/module.yml +74 -0
  100. package/modules/tool-surface/module.yml +67 -0
  101. package/package.json +50 -80
  102. package/templates/10-pre-step.yml +26 -22
  103. package/templates/14-first-turn-anchor.yml +25 -21
  104. package/templates/15-guide-auto.yml +34 -19
  105. package/templates/16-custom-fallback.yml +27 -15
  106. package/templates/18-placeholder-env-facts.yml +23 -14
  107. package/templates/20-system-section.yml +20 -11
  108. package/templates/30-runtime-context.yml +13 -7
  109. package/templates/40-agent-request.yml +11 -8
  110. package/templates/50-llm-stream.yml +14 -6
  111. package/templates/60-tool-pipeline.yml +15 -9
  112. package/templates/65-turn-stop.yml +19 -12
  113. package/templates/66-subagent-start.yml +12 -7
  114. package/templates/70-subagent-maintenance.yml +35 -29
  115. package/templates/75-subagent-end.yml +10 -5
  116. package/templates/80-tool-surface.yml +66 -0
  117. package/templates/policies/legacy-defaults.yml +34 -0
  118. package/templates/tools/50-delegate-worldbook.yml +1 -1
  119. package/engine/compositions/source/local/prompt-config-engine.yml +0 -7
  120. package/engine/prompt-config-engine.mjs +0 -104
  121. package/preset/pt-cordis/preset.yml +0 -43
  122. package/preset/pt-cordis/skills/cordis-composition-reference/SKILL.md +0 -29
  123. package/preset/pt-cordis/skills/cordis-composition-reference/references/packages.md +0 -501
  124. package/preset/pt-cordis/skills/cordis-plugin-development/SKILL.md +0 -38
  125. package/preset/pt-cordis/skills/cordis-plugin-development/references/host-plugin.md +0 -60
  126. package/preset/pt-cordis/skills/cordis-plugin-development/references/mcp-bundle.md +0 -5
  127. package/preset/pt-cordis/skills/cordis-plugin-development/references/ui-plugin.md +0 -13
  128. package/preset/pt-cordis/skills/cordis-plugin-development/references/verification.md +0 -5
  129. package/preset/pt-cordis/skills/cordis-plugin-development/templates/decoration/client.js +0 -22
  130. package/preset/pt-cordis/skills/cordis-plugin-development/templates/decoration/cordis.patch.yml +0 -3
  131. package/preset/pt-cordis/skills/cordis-plugin-development/templates/decoration/index.js +0 -2
  132. package/preset/pt-cordis/skills/cordis-plugin-development/templates/decoration/package.json +0 -15
  133. package/preset/pt-cordis/skills/cordis-plugin-development/templates/mcp/cordis.patch.yml +0 -8
  134. package/preset/pt-cordis/skills/cordis-plugin-development/templates/mcp/package.json +0 -7
  135. package/preset/pt-cordis/skills/editing-cordis-compositions/SKILL.md +0 -84
  136. package/preset/pt-custom/preset.yml +0 -15
  137. package/preset/pt-minimal/preset.yml +0 -27
  138. package/preset/pt-ptc/preset.yml +0 -45
  139. package/preset/pt-standard/preset.yml +0 -43
@@ -0,0 +1,44 @@
1
+ /**
2
+ * 分支语法的唯一展开器:`if`/`then`/`else` 是当前名,`when`/`do` 是兼容输入。
3
+ *
4
+ * 规则(`rule-spec.mjs`)与触发器声明(`trigger-spec.mjs`)共用这一份实现——
5
+ * 两套入口必须是同一套语义,否则同一个模块换个入口就换行为。
6
+ */
7
+
8
+ const record = value => value !== null && typeof value === 'object' && !Array.isArray(value)
9
+
10
+ /** 分支节点:占动作位、没有 `kind`,但带 `if`/`then`/`else` 之一。 */
11
+ export const isBranchNode = node => record(node) && node.kind === undefined
12
+ && (node.if !== undefined || node.then !== undefined || node.else !== undefined)
13
+
14
+ /** 多个条件按声明序合取;空数组 = 无条件(`compileWhen(undefined)` 直接返回 undefined)。 */
15
+ export function conjunction(conditions) {
16
+ if (conditions.length === 0) return undefined
17
+ return conditions.length === 1 ? conditions[0] : { all: [...conditions] }
18
+ }
19
+
20
+ /**
21
+ * 把一份动作声明展开为扁平的「动作 + 自身分支条件」列表。
22
+ *
23
+ * - 普通动作原样带出,分支条件 = `outer` 的合取(空 = 无条件);
24
+ * - 分支节点的 `then` 追加本层 `if`、`else` 追加 `not(if)`——互斥由结构保证,不由作者手写;
25
+ * - 返回顺序即声明序(then 在前、else 在后);
26
+ * - `bypass` 标记该动作来自**声明级** `else`:它的条件已含 `not(if)`,不能再叠加声明级判定。
27
+ */
28
+ export function expandActions(list, options = {}, label) {
29
+ if (!Array.isArray(list)) throw new TypeError(`${label} must be an array`)
30
+ const { outer = [], bypass = false } = options
31
+ const out = []
32
+ for (const [index, node] of list.entries()) {
33
+ const at = `${label}[${index}]`
34
+ if (isBranchNode(node)) {
35
+ if (node.if === undefined) throw new TypeError(`${at}: a branch needs if`)
36
+ if (node.then === undefined) throw new TypeError(`${at}: a branch needs then`)
37
+ out.push(...expandActions(node.then, { outer: [...outer, node.if], bypass }, `${at}.then`))
38
+ if (node.else !== undefined) out.push(...expandActions(node.else, { outer: [...outer, { not: node.if }], bypass }, `${at}.else`))
39
+ continue
40
+ }
41
+ out.push({ node, conditions: outer, bypass })
42
+ }
43
+ return out
44
+ }
@@ -2,10 +2,7 @@
2
2
  export const name = "character-tools"
3
3
 
4
4
  export function apply(ctx) {
5
- const service = ctx.get("pt-character-tools")
6
- if (service === null || service === undefined || typeof service.mount !== "function") {
7
- ctx.logger?.warn(name + ": service unavailable; character tools not mounted for this preset")
8
- return
9
- }
10
- ctx.effect(() => service.mount(ctx), name + ": mount")
5
+ ctx.inject(["pt-character-tools"], (scopeCtx) => {
6
+ scopeCtx.effect(() => scopeCtx.get("pt-character-tools").mount(scopeCtx), name + ": mount")
7
+ })
11
8
  }
@@ -23,7 +23,7 @@
23
23
  *
24
24
  * GATE MODE (strict two-phase stabilization extension, source: xiaobright/dsh-anchored-standard
25
25
  * MIT + phase-1 quarantine): `promoteGate: true` gates the promotion on the
26
- * first reasoning block classifying minimal-like (`we` present, no `let me`),
26
+ * first reasoning block matching the caller's positive and negative patterns,
27
27
  * with a `maxPromoteSteps` fallback supplied by the caller's config; `promoteAfterFirstResponse:
28
28
  * true` promotes a tool-less first response once it has responded, and also
29
29
  * releases an anchor-gated session when its first turn ends. Gate mode uses
@@ -34,24 +34,41 @@
34
34
 
35
35
  import { sessionEvents, sessionState } from './shared.mjs'
36
36
 
37
- /** 首段 reasoning 块分类(严格门控扩展):we 且无 let me = minimal-like。 */
38
- export function classifyReasoning(text) {
39
- const trimmed = String(text ?? '').trim()
40
- const we = [...trimmed.matchAll(/\bwe\b/gi)].length
41
- const letMe = [...trimmed.matchAll(/\blet me\b/gi)].length
42
- const metrics = { we, letMe }
43
- if (we > 0 && letMe === 0) return { label: 'minimal-like', score: 4, metrics }
44
- if (letMe > 0) return { label: 'standard-like', score: -4, metrics }
45
- return { label: 'ambiguous', score: 0, metrics }
37
+ /** 匹配内容与大小写均由调用方显式声明;空 pattern 不承担任何业务识别。 */
38
+ function reasoningClassifier(options = {}) {
39
+ const flags = options.reasoningFlags ?? ''
40
+ if (typeof flags !== 'string') throw new TypeError('reasoningFlags must be a string')
41
+ const compile = (key) => {
42
+ const pattern = options[key]
43
+ if (pattern == null || pattern === '') return undefined
44
+ if (typeof pattern !== 'string') throw new TypeError(`${key} must be a string`)
45
+ return new RegExp(pattern, flags.includes('g') ? flags : `${flags}g`)
46
+ }
47
+ const positive = compile('reasoningPattern')
48
+ const negative = compile('reasoningNegativePattern')
49
+ return text => {
50
+ const trimmed = String(text ?? '').trim()
51
+ // 旧诊断返回字段保留;两项现在分别计数调用方的正、负模式。分数不参与晋升。
52
+ const we = positive === undefined ? 0 : [...trimmed.matchAll(positive)].length
53
+ const letMe = negative === undefined ? 0 : [...trimmed.matchAll(negative)].length
54
+ const metrics = { we, letMe }
55
+ if (we > 0 && letMe === 0) return { label: 'minimal-like', score: 4, metrics }
56
+ if (letMe > 0) return { label: 'standard-like', score: -4, metrics }
57
+ return { label: 'ambiguous', score: 0, metrics }
58
+ }
46
59
  }
47
60
 
61
+ export function classifyReasoning(text, options = {}) { return reasoningClassifier(options)(text) }
62
+
48
63
  /** 首段 reasoning 块是否为 minimal-like(后续块不覆盖首个标准样块)。 */
49
- export function hasAnchoredReasoning(content) {
64
+ function firstReasoningMatches(content, classify) {
50
65
  if (!Array.isArray(content)) return false
51
66
  const first = content.find((block) => block?.type === 'reasoning')
52
- return first !== undefined && classifyReasoning(first.text).label === 'minimal-like'
67
+ return first !== undefined && classify(first.text).label === 'minimal-like'
53
68
  }
54
69
 
70
+ export function hasAnchoredReasoning(content, options = {}) { return firstReasoningMatches(content, reasoningClassifier(options)) }
71
+
55
72
  /** True only when compaction completed and changed the model-visible surface. */
56
73
  export function isSuccessfulCompactionEnd(event) {
57
74
  return event?.type === 'compaction/end' && event.data?.error === undefined
@@ -62,6 +79,7 @@ export function createEpochPromotion(promoteEvents, options = {}) {
62
79
  const includeSubagents = options.includeSubagents === true
63
80
  const promoteGate = options.promoteGate === true
64
81
  const promoteAfterFirstResponse = options.promoteAfterFirstResponse === true
82
+ const classify = reasoningClassifier(options)
65
83
  // 门控回退步数由调用方配置提供(tool-bootstrap 在开启门控时做必填校验):
66
84
  // 引擎不内置默认;未提供时步数兜底不生效,只按 anchored 判定。
67
85
  const maxPromoteSteps = options.maxPromoteSteps
@@ -115,7 +133,7 @@ export function createEpochPromotion(promoteEvents, options = {}) {
115
133
  else if (event.type === 'turn/end') entry.turnEnded = true
116
134
  else if (event.type === 'assistant/message') {
117
135
  entry.responded = true
118
- if (!entry.anchored) entry.anchored = hasAnchoredReasoning(event.data?.message?.content)
136
+ if (!entry.anchored) entry.anchored = firstReasoningMatches(event.data?.message?.content, classify)
119
137
  }
120
138
  if (decideGate(entry)) entry.promoted = true
121
139
  return entry
@@ -1,6 +1,6 @@
1
1
  # module: agent-instructions
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: agent-instructions
@@ -1,6 +1,6 @@
1
1
  # module: command-goal
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: command-goal
@@ -1,6 +1,6 @@
1
1
  # module: compaction
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: compaction
@@ -1,6 +1,6 @@
1
1
  # module: delegation-ptc
2
2
  # source: master/packages/bundle/web-app/presets/ptc.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: delegation
@@ -1,6 +1,6 @@
1
1
  # module: delegation
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: delegation
@@ -1,6 +1,6 @@
1
1
  # module: persistent-shell
2
2
  # source: master/packages/bundle/web-app/presets/minimal.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: persistent-shell
@@ -1,6 +1,6 @@
1
1
  # module: planning
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: planning
@@ -1,6 +1,6 @@
1
1
  # module: skill-filesystem-cordis
2
2
  # source: master/packages/bundle/web-app/presets/cordis.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: skill-filesystem
@@ -1,6 +1,6 @@
1
1
  # module: skill-filesystem
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: skill-filesystem
@@ -1,6 +1,6 @@
1
1
  # module: tool-ask-user
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-ask-user
@@ -1,6 +1,6 @@
1
1
  # module: tool-bash
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-bash
@@ -1,6 +1,6 @@
1
1
  # module: tool-cordis
2
2
  # source: master/packages/bundle/web-app/presets/cordis.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-cordis
@@ -1,6 +1,6 @@
1
1
  # module: tool-fs-search
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-fs-search
@@ -1,6 +1,6 @@
1
1
  # module: tool-fs
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-fs
@@ -1,6 +1,6 @@
1
1
  # module: tool-goal
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-goal
@@ -1,6 +1,6 @@
1
1
  # module: tool-jobs
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-jobs
@@ -1,6 +1,6 @@
1
1
  # module: tool-plugin-manager-disabled
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-plugin-manager
@@ -1,6 +1,6 @@
1
1
  # module: tool-plugin-manager
2
2
  # source: master/packages/bundle/web-app/presets/cordis.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-plugin-manager
@@ -1,6 +1,6 @@
1
1
  # module: tool-present
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: present
@@ -1,6 +1,6 @@
1
1
  # module: tool-presentation
2
2
  # source: master/packages/bundle/web-app/presets/ptc.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-presentation
@@ -1,6 +1,6 @@
1
1
  # module: tool-pwsh
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-pwsh
@@ -1,6 +1,6 @@
1
1
  # module: tool-skill
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-skill
@@ -1,6 +1,6 @@
1
1
  # module: tool-todo
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-todo
@@ -1,6 +1,6 @@
1
1
  # module: tool-web
2
2
  # source: master/packages/bundle/web-app/presets/standard.patch.yml
3
- # commit: c36a83ff6bb95e3f82cf79f9be7c724270a8aa61
3
+ # commit: 4878cdabd87d4041bdaff61d04c966883b9fd07a
4
4
  # local patches: 0
5
5
 
6
6
  - id: tool-web
@@ -0,0 +1,11 @@
1
+ # module: dev-tool-search
2
+ # source: engine/compositions/source/local/dev-tool-search.yml (本地附加,非官方模块)
3
+ #
4
+ # 工具面的按需发现与解锁。与 assembly 动作的 allowFrom 配对使用:
5
+ # 本工具把解锁名写进持久 tool/call 参数 → allowFrom 读回 → 下次请求起生效。
6
+ # 只挂本行而不配 allowFrom 的话,解锁是一次性的(当次请求用完即被裁掉)。
7
+ #
8
+ # 常驻集由模板声明(见 templates/ 的工具面收窄模板),本行只负责发现入口。
9
+
10
+ - id: dev-tool-search
11
+ name: ./engine/dev-tool-search.mjs
@@ -6,10 +6,31 @@
6
6
  # opt-in:enabled 默认 false(与原 instructionHint 默认 false 同值),由参数桥
7
7
  # params.instructionHint(→ 本行 enabled)或本行 config.enabled: true 打开;
8
8
  # 相位词汇与 tool-bootstrap / promoted-code-mode 同源(compaction-epoch.mjs)。
9
+ #
10
+ # 四个模板必须随行给全(2026-10-05 修):`instruction-hint.mjs#apply` 的首行是
11
+ # `if (!enabled || templateOf(source, 'messageTemplate').trim().length === 0) return`
12
+ # 而本行此前只配了 enabled/promoteOn/includeSubagents —— 于是把开关打开**不注册任何
13
+ # 转换**:配置合法、零效果、零报错(与 count.delegated 的静默失效同类)。模板正文取自
14
+ # templates/policies/legacy-defaults.yml#instructionHint,与 rules-migration.ts:102
15
+ # 的迁移默认值同源;两处必须一致,否则「迁移进来的定义」与「新装的组合源」行为分叉。
16
+ # legacy-defaults.yml 自身标注「引擎运行时不得读取」,所以这里必须是实体而非引用。
17
+ #
18
+ # includeSubagents: true —— 子代理首次请求即视为已晋升(官方相位语义),所以子代理
19
+ # 从第 1 轮就拿提示而非全文。主会话则是首个工具调用/助手消息之后才降级(promoteOn)。
9
20
 
10
21
  - id: instruction-hint
11
22
  name: ./engine/instruction-hint.mjs
12
23
  config:
13
24
  enabled: false
14
25
  promoteOn: either
15
- includeSubagents: false
26
+ includeSubagents: true
27
+ projectTemplate: "Reference documents exist: {{FILES}} (project root: {{ROOT}})."
28
+ globalTemplate: "A user reference document exists: {{FILES}}."
29
+ suffixTemplate: They are reference documents about the user's environment and
30
+ workspace conventions, not task instructions. Reading the relevant file
31
+ before workspace tasks is recommended, but consult them only when you need
32
+ those details; the task itself never depends on them.
33
+ messageTemplate: |-
34
+ <system-reminder>
35
+ Reference documents exist: {{FILES}}. {{SUFFIX}}
36
+ </system-reminder>
@@ -0,0 +1,6 @@
1
+ # module: rule-engine
2
+ # 单一规则分发入口;插件配装通道直接挂载同一编译器时跳过此行。
3
+ - id: rule-engine
4
+ name: ./engine/rule-engine.mjs
5
+ config:
6
+ rulesFile: ../rules.yml
@@ -14,7 +14,7 @@
14
14
  import { extractText, sessionEvents } from './shared.mjs'
15
15
 
16
16
  /** subject → 载荷字段名。改这里等于改所有层的匹配对象。 */
17
- const SUBJECT_FIELDS = {
17
+ export const SUBJECT_FIELDS = {
18
18
  toolArgs: 'argsText',
19
19
  toolResult: 'resultText',
20
20
  userMessage: 'userText',
@@ -54,11 +54,24 @@ export function toolArgsText(args) {
54
54
  }
55
55
  }
56
56
 
57
- /** pre-step 的缺省匹配对象:本批用户消息的文本。 */
57
+ /**
58
+ * pre-step 的缺省匹配对象:本批**真实对话**的用户消息文本。
59
+ *
60
+ * 只收真人输入:引擎自己注入的消息同样是 user-role(`executor.mjs` 的
61
+ * `role: PRE_STEP_ROLE`、`pluginMessage` 的 `source` 是 `plugin:<name>` 生产者身份),
62
+ * 把它们算进来会让 `text.match` 匹配到自己注入过的正文——规则正文里出现「重构」
63
+ * 「实现」这类词就会自我命中,且命中判定在去重之前,`dedupe` 挡不住。
64
+ * 过滤判据与 `st-world-book.mjs#stChatMessages` 的同名约定一致(那是最早做对的一处),
65
+ * 两处必须保持同语义。
66
+ */
58
67
  export function userMessagesText(messages) {
59
68
  if (!Array.isArray(messages)) return ''
60
69
  return messages
61
- .filter((message) => message?.role === 'user')
70
+ .filter((message) => message?.role === 'user'
71
+ && message.source?.plugin === undefined
72
+ && message.source?.kind !== 'plugin'
73
+ && !(typeof message.source?.kind === 'string' && message.source.kind.startsWith('plugin:'))
74
+ && (message.source?.kind === undefined || message.source.kind === 'user'))
62
75
  .map((message) => extractText(message))
63
76
  .filter((text) => text.length > 0)
64
77
  .join('\n')
@@ -0,0 +1,32 @@
1
+ import { createAnchorMatcher } from '../anchor-match.mjs'
2
+ import { sessionEvents, sessionState } from '../shared.mjs'
3
+ import { sessionOf } from './subject.mjs'
4
+ import { boundOf, keyList } from './values.mjs'
5
+
6
+ /** 首条 assistant reasoning 的确认事实;未到达时不缓存,无 id 会话不共享状态。 */
7
+ export function createAnchorState(options = {}) {
8
+ const matcher = createAnchorMatcher({ keys: keyList(options.keys, 'anchor.keys'), mode: 'prefix' })
9
+ const confirmedBySession = sessionState(undefined, () => false)
10
+ return session => {
11
+ const assistants = sessionEvents(session).filter(event => event.type === 'assistant/message')
12
+ let confirmed = confirmedBySession.peek(session)
13
+ if (confirmed === undefined && assistants.length > 0) {
14
+ const reasoning = (assistants[0].data?.message?.content ?? []).find(block => block.type === 'reasoning')
15
+ confirmed = reasoning !== undefined && matcher.scan(String(reasoning.text ?? '')).active
16
+ confirmedBySession.set(session, confirmed)
17
+ }
18
+ return { confirmed: confirmed === true, assistantRounds: assistants.length }
19
+ }
20
+ }
21
+
22
+ /** 确认即命中;可选 fallbackAfter 表示超过指定 assistant 消息数后也允许。 */
23
+ export function createAnchorPredicate(options = {}) {
24
+ const inspect = createAnchorState(options)
25
+ const fallbackAfter = boundOf(options.fallbackAfter, 'anchor.fallbackAfter')
26
+ const predicate = payload => {
27
+ const status = inspect(sessionOf(payload))
28
+ return status.confirmed || (fallbackAfter !== undefined && status.assistantRounds > fallbackAfter)
29
+ }
30
+ predicate.kind = 'anchor'
31
+ return predicate
32
+ }
@@ -0,0 +1,47 @@
1
+ import { agentOf, sessionOf } from './subject.mjs'
2
+ import { SUBJECT_FIELDS } from '../condition.mjs'
3
+
4
+ /** 缺少真实事件事实不是 false;尤其不能经 not 反转成允许。 */
5
+ export const UNAVAILABLE = Symbol('condition-input-unavailable')
6
+
7
+ export function conditionInputAvailable(kind, options, payload) {
8
+ const agent = agentOf(payload)
9
+ const session = sessionOf(payload)
10
+ if (['phase', 'count', 'session', 'anchor'].includes(kind)) {
11
+ return session != null && typeof session.snapshotEvents === 'function' && (kind !== 'phase' || agent?.session != null)
12
+ }
13
+ if (kind === 'preset') return agent?.ctx != null
14
+ if (kind === 'names') {
15
+ const name = typeof payload === 'string' ? payload : payload?.name
16
+ return typeof name === 'string' && name.length > 0
17
+ }
18
+ if (kind === 'source') return payload?.source !== null && typeof payload?.source === 'object' && !Array.isArray(payload.source)
19
+ if (kind === 'text') {
20
+ if (typeof payload === 'string') return true
21
+ const field = Object.hasOwn(SUBJECT_FIELDS, options.subject) ? SUBJECT_FIELDS[options.subject] : undefined
22
+ if (field === undefined || typeof payload?.[field] !== 'string') return false
23
+ // 归一化器可把缺载荷投影为空文本;保留原参数表时必须区分缺事实与确实为空。
24
+ if (Array.isArray(payload.args)) {
25
+ if (options.subject === 'toolArgs') return payload.args[0] != null && Object.hasOwn(payload.args[0], 'arguments')
26
+ if (options.subject === 'toolResult') return payload.args.length > 1 && payload.args[1] !== undefined
27
+ if (options.subject === 'userMessage' && payload.channel === 'agent/pre-step') return Array.isArray(payload.args[0]?.messages)
28
+ if (options.subject === 'userMessage' && payload.channel === 'agent/inbox/inserted') return payload.args[0]?.message != null
29
+ if (options.subject === 'assistantText') return typeof session?.snapshotEvents === 'function'
30
+ if (options.subject === 'subagentInfo') return payload.args[0] != null
31
+ }
32
+ return true
33
+ }
34
+ if (kind === 'scope') {
35
+ if (options.audience !== undefined && session == null) return false
36
+ const model = payload?.model ?? agent?.options?.model
37
+ if (options.modelScope !== undefined && options.modelScope !== 'all' && (typeof model !== 'string' || model.length === 0)) return false
38
+ }
39
+ return true
40
+ }
41
+
42
+ export function withAvailableInput(kind, options, predicate) {
43
+ const wrapped = payload => conditionInputAvailable(kind, options, payload) ? predicate(payload) : UNAVAILABLE
44
+ wrapped.kind = predicate.kind
45
+ if (typeof predicate.observe === 'function') wrapped.observe = (session, event) => predicate.observe(session, event)
46
+ return wrapped
47
+ }
@@ -0,0 +1,83 @@
1
+ import { MATCH_LOGIC } from '../anchor-match.mjs'
2
+ import { UNAVAILABLE } from './availability.mjs'
3
+ const COMPOSITE_OPERATORS = Object.values(MATCH_LOGIC)
4
+
5
+ export function composite(node) {
6
+ if (typeof node === 'function') return node
7
+ if (node === null || typeof node !== 'object' || Array.isArray(node)) {
8
+ throw new TypeError(`predicates: a composite must be a predicate or { ${COMPOSITE_OPERATORS.join(' | ')} }`)
9
+ }
10
+ const unknown = Object.keys(node).filter((key) => !COMPOSITE_OPERATORS.includes(key))
11
+ if (unknown.length > 0) {
12
+ throw new TypeError(`predicates: unknown composite key(s) ${unknown.join(', ')} — allowed: ${COMPOSITE_OPERATORS.join(', ')}`)
13
+ }
14
+ const declared = COMPOSITE_OPERATORS.filter((key) => node[key] !== undefined)
15
+ if (declared.length !== 1) {
16
+ throw new TypeError(`predicates: a composite node must declare exactly one of ${COMPOSITE_OPERATORS.join(', ')}`)
17
+ }
18
+ const operator = declared[0]
19
+ if (operator === MATCH_LOGIC.NOT) {
20
+ const child = composite(node[operator])
21
+ const predicate = (payload) => {
22
+ const result = child(payload)
23
+ return result === UNAVAILABLE ? UNAVAILABLE : !result
24
+ }
25
+ predicate.kind = 'composite'
26
+ if (typeof child.observe === 'function') {
27
+ predicate.observe = (session, event) => child.observe(session, event)
28
+ }
29
+ return predicate
30
+ }
31
+ const list = node[operator]
32
+ if (!Array.isArray(list) || list.length === 0) {
33
+ throw new TypeError(`predicates: composite ${operator} needs a non-empty array of predicates`)
34
+ }
35
+ const children = list.map(composite)
36
+ const predicates = {
37
+ [MATCH_LOGIC.ANY]: (payload) => {
38
+ let unknown = false
39
+ for (const child of children) {
40
+ const result = child(payload)
41
+ if (result === UNAVAILABLE) unknown = true
42
+ else if (result) return true
43
+ }
44
+ return unknown ? UNAVAILABLE : false
45
+ },
46
+ [MATCH_LOGIC.ALL]: (payload) => {
47
+ let unknown = false
48
+ for (const child of children) {
49
+ const result = child(payload)
50
+ if (result === UNAVAILABLE) unknown = true
51
+ else if (!result) return false
52
+ }
53
+ return unknown ? UNAVAILABLE : true
54
+ },
55
+ [MATCH_LOGIC.NOT_ANY]: (payload) => {
56
+ let unknown = false
57
+ for (const child of children) {
58
+ const result = child(payload)
59
+ if (result === UNAVAILABLE) unknown = true
60
+ else if (result) return false
61
+ }
62
+ return unknown ? UNAVAILABLE : true
63
+ },
64
+ }
65
+ const predicate = predicates[operator]
66
+ if (predicate === undefined) {
67
+ throw new TypeError(`predicates: composite ${operator} is not a supported operator`)
68
+ }
69
+ predicate.kind = 'composite'
70
+ // 组合层必须**转发子谓词的 observe**(B7 T1 的跨能力缺口修复):两条挂载路径的观察器
71
+ // 接线都按 `when.observe` 过滤(`trigger.mjs` 的 `wireTriggerObservers`),被组合包住的
72
+ // phase / count / session 谓词否则永远收不到活的 `session/event`——状态按 `session.id`
73
+ // 缓存后不再重扫(`shared.mjs` 的 `sessionMapGet`),判定会停在冷扫那一刻(计数恒旧值、
74
+ // 相位永不晋升)。`phase` 有 `subscribe: false` 可绕(代价是每次判定冷扫),
75
+ // `count` / `session` 没有该档,所以这条转发是它们唯一的活路。
76
+ const observers = children.filter((child) => typeof child.observe === 'function')
77
+ if (observers.length > 0) {
78
+ predicate.observe = (session, event) => {
79
+ for (const child of observers) child.observe(session, event)
80
+ }
81
+ }
82
+ return predicate
83
+ }