dsh-plugin-prompt-tool 1.0.0 → 2.0.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.
- package/README.md +38 -29
- package/engine/actions/append-context.mjs +49 -0
- package/engine/actions/assembly.mjs +150 -0
- package/engine/actions/catalog.mjs +92 -0
- package/engine/actions/content.mjs +205 -0
- package/engine/actions/decision.mjs +54 -0
- package/engine/actions/examples.mjs +11 -0
- package/engine/actions/guard.mjs +80 -0
- package/engine/actions/inbox-prepend.mjs +37 -0
- package/engine/actions/index.mjs +100 -0
- package/engine/actions/inject-text.mjs +22 -0
- package/engine/actions/pre-step-filter.mjs +55 -0
- package/engine/actions/registration.mjs +168 -0
- package/engine/actions/request-params.mjs +32 -0
- package/engine/actions/sdk-strip.mjs +30 -0
- package/engine/actions/shared.mjs +71 -0
- package/engine/actions.mjs +2 -931
- package/engine/branch.mjs +44 -0
- package/engine/compaction-epoch.mjs +31 -13
- package/engine/compositions/source/local/dev-tool-search.yml +11 -0
- package/engine/compositions/source/local/instruction-hint.yml +22 -1
- package/engine/compositions/source/local/rule-engine.yml +6 -0
- package/engine/condition.mjs +16 -3
- package/engine/conditions/anchor.mjs +32 -0
- package/engine/conditions/availability.mjs +47 -0
- package/engine/conditions/composite.mjs +83 -0
- package/engine/conditions/count.mjs +140 -0
- package/engine/conditions/evaluation.mjs +41 -0
- package/engine/conditions/examples.mjs +11 -0
- package/engine/conditions/index.mjs +85 -0
- package/engine/conditions/names.mjs +21 -0
- package/engine/conditions/phase.mjs +54 -0
- package/engine/conditions/preset.mjs +94 -0
- package/engine/conditions/scope.mjs +18 -0
- package/engine/conditions/session.mjs +22 -0
- package/engine/conditions/source.mjs +63 -0
- package/engine/conditions/subject.mjs +121 -0
- package/engine/conditions/text.mjs +44 -0
- package/engine/conditions/values.mjs +32 -0
- package/engine/dev-tool-search.mjs +213 -0
- package/engine/executor.mjs +55 -6
- package/engine/fillers.mjs +23 -16
- package/engine/instruction-hint.mjs +34 -22
- package/engine/layers.mjs +135 -49
- package/engine/order.mjs +4 -1
- package/engine/predicates.mjs +2 -753
- package/engine/rule-engine.mjs +40 -0
- package/engine/rule-runtime.mjs +110 -0
- package/engine/rule-spec.mjs +187 -0
- package/engine/schema.mjs +16 -5
- package/engine/shared.mjs +1 -1
- package/engine/strategies.mjs +2 -235
- package/engine/subagent-tool-policy-core.mjs +7 -7
- package/engine/subagent-tool-policy.mjs +20 -10
- package/engine/tool-config-engine.mjs +53 -32
- package/engine/trigger-spec.mjs +49 -133
- package/lib/client.js +11117 -10860
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +82 -139
- package/lib/index.mjs +826 -1087
- package/lib/migrate-rules.d.mts +1 -0
- package/lib/migrate-rules.mjs +39 -0
- package/lib/module-package-CHPFweqK.mjs +2 -0
- package/lib/module-package-Cnd1_mwx.mjs +2872 -0
- package/lib/{paths-BgL42sSM.d.mts → paths-CyP0IkaM.d.mts} +223 -108
- package/lib/preset-transfer.d.mts +2 -2
- package/lib/preset-transfer.mjs +3 -2
- package/lib/{module-package-Cm3fHHlp.mjs → rules-migration-DJ6vASB5.mjs} +13696 -15557
- package/modules/ponytail/module.yml +381 -147
- package/modules/skill-surface/module.yml +74 -0
- package/modules/tool-surface/module.yml +67 -0
- package/package.json +5 -1
- package/templates/10-pre-step.yml +26 -22
- package/templates/14-first-turn-anchor.yml +25 -21
- package/templates/15-guide-auto.yml +34 -19
- package/templates/16-custom-fallback.yml +27 -15
- package/templates/18-placeholder-env-facts.yml +23 -14
- package/templates/20-system-section.yml +16 -10
- package/templates/30-runtime-context.yml +13 -7
- package/templates/40-agent-request.yml +11 -8
- package/templates/50-llm-stream.yml +14 -6
- package/templates/60-tool-pipeline.yml +15 -9
- package/templates/65-turn-stop.yml +19 -12
- package/templates/66-subagent-start.yml +12 -7
- package/templates/70-subagent-maintenance.yml +35 -29
- package/templates/75-subagent-end.yml +10 -5
- package/templates/80-tool-surface.yml +66 -0
- package/templates/policies/legacy-defaults.yml +34 -0
- package/engine/compositions/source/local/prompt-config-engine.yml +0 -7
- package/engine/prompt-config-engine.mjs +0 -104
- package/engine/trigger-editor-meta.mjs +0 -48
- package/modules/ponytail/configs/0000-ponytail-rules.yml +0 -102
- package/modules/ponytail/configs/0010-ponytail-level-full.yml +0 -19
- package/modules/ponytail/configs/0020-ponytail-level-lite.yml +0 -19
- package/modules/ponytail/configs/0030-ponytail-level-ultra.yml +0 -19
package/engine/trigger-spec.mjs
CHANGED
|
@@ -1,141 +1,42 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* trigger-spec — 声明编译器(B7 T1):把**纯数据**的触发器声明编译成可注册的形状。
|
|
3
|
-
*
|
|
4
|
-
* 分工:`predicates.mjs` 提供判断原语、`actions.mjs` 提供动作、`trigger.mjs` 提供调度机制,
|
|
5
|
-
* 本文件只做「数据 → 函数」这一步,**不含任何判断或执行的实现**。
|
|
6
|
-
*
|
|
7
|
-
* ## 词汇原样透传(这是本文件最重要的约束)
|
|
8
|
-
*
|
|
9
|
-
* `when` 的键要么是组合运算符(`any` / `all` / `not` / `notAny`),要么是七类原语之一
|
|
10
|
-
* (`text` / `phase` / `source` / `count` / `names` / `session` / `preset`),**值原样传给对应的
|
|
11
|
-
* `createXxxPredicate`**。声明层**不翻译、不改名、不补默认**——一旦这里长出第二套词汇,
|
|
12
|
-
* 「文档里写的选项」与「谓词真正接受的选项」就会开始漂移,而这正是本项目要收敛的问题。
|
|
13
|
-
*
|
|
14
|
-
* ## 为什么 `when` 省略 = 无条件
|
|
15
|
-
*
|
|
16
|
-
* `when` 是**收窄**条件:不写表示「这个动作在该通道上总是执行」。这与「写一个恒真谓词」
|
|
17
|
-
* 在行为上等价,但省略更好读;编译器对省略返回 `undefined`,注册侧据此跳过判定(零开销)。
|
|
18
|
-
*
|
|
19
|
-
* ## 与 `mountTriggers` 的关系
|
|
20
|
-
*
|
|
21
|
-
* `trigger.mjs` 的 `mountTriggers` 要求 `do` 是**函数**,而声明的 `do` 是**动作声明**;
|
|
22
|
-
* B3 收口时两者从未对接。本文件不去接那条线(查证过:`inject-text` 与 `guard` 不经
|
|
23
|
-
* `on(...)` 注册,"执行体"抽不出来),而是编译出 `{when, actions}` 交给
|
|
24
|
-
* `registerAction(ctx, action, { when })` ——判定由动作侧按固定执行阶段提供。
|
|
25
|
-
* 调度层面仍复用 `trigger.mjs` 的 `orderTriggers` / `registrationOptions`。
|
|
26
|
-
*/
|
|
27
|
-
import {
|
|
28
|
-
composite,
|
|
29
|
-
createCountPredicate,
|
|
30
|
-
createNameListPredicate,
|
|
31
|
-
createPhasePredicate,
|
|
32
|
-
createPresetPredicate,
|
|
33
|
-
createSessionStatePredicate,
|
|
34
|
-
createSourcePredicate,
|
|
35
|
-
createTextPredicate,
|
|
36
|
-
} from './predicates.mjs'
|
|
1
|
+
/** 旧 triggers 声明供离线迁移与历史契约验证;新运行时只编译 rules。 */
|
|
37
2
|
import { ACTION_KINDS, actionExecutionPoint, prepareAction, registerAction } from './actions.mjs'
|
|
38
3
|
import { WATERFALL_POSITIONS, orderTriggers, registrationOptions, wireTriggerObservers } from './trigger.mjs'
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
export
|
|
42
|
-
|
|
43
|
-
phase: createPhasePredicate,
|
|
44
|
-
source: createSourcePredicate,
|
|
45
|
-
count: createCountPredicate,
|
|
46
|
-
names: createNameListPredicate,
|
|
47
|
-
session: createSessionStatePredicate,
|
|
48
|
-
preset: createPresetPredicate,
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
/** 组合运算符(与 `composite` 的词汇同源,不另立别名)。 */
|
|
52
|
-
export const COMPOSITE_OPERATORS = Object.freeze(['any', 'all', 'not', 'notAny'])
|
|
53
|
-
|
|
54
|
-
/** 声明允许的字段(未知字段 fail loud:写错键名是最容易被静默忽略的一类错)。 */
|
|
55
|
-
const DECLARATION_FIELDS = Object.freeze(['id', 'channel', 'channelOrder', 'waterfallPosition', 'phase', 'when', 'do'])
|
|
56
|
-
|
|
57
|
-
/** 判定/动作在 `next()` 之前还是之后执行。 */
|
|
4
|
+
import { compileWhen } from './conditions/index.mjs'
|
|
5
|
+
import { conjunction, expandActions } from './branch.mjs'
|
|
6
|
+
export { compileWhen, COMPOSITE_OPERATORS, PREDICATE_FACTORIES } from './conditions/index.mjs'
|
|
7
|
+
const DECLARATION_FIELDS = Object.freeze(['id', 'channel', 'channelOrder', 'waterfallPosition', 'phase', 'if', 'then', 'else', 'when', 'do'])
|
|
58
8
|
const ACTION_PHASES = Object.freeze(['before-next', 'after-next'])
|
|
59
9
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return value
|
|
10
|
+
/** `then`/`do` 归一化为动作声明数组;分支节点留到 `expandActions` 展开。 */
|
|
11
|
+
function actionList(value, label) {
|
|
12
|
+
const list = Array.isArray(value) ? value : [value]
|
|
13
|
+
if (list.length === 0) throw new TypeError(`${label} must be an action declaration or a non-empty array of them`)
|
|
14
|
+
return list
|
|
66
15
|
}
|
|
67
16
|
|
|
68
|
-
/**
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
* - 组合节点:`{ any: [节点…] }` / `{ all: [节点…] }` / `{ notAny: [节点…] }` / `{ not: 节点 }`
|
|
73
|
-
* - 原语节点:`{ <类别>: <选项对象> }`
|
|
74
|
-
* **一个节点只能声明一个键**——混合声明(如同时给 `all` 与 `not`)在编译期抛错,
|
|
75
|
-
* 于是优先级永远是显式的树形嵌套,而不是靠"先算 not 再算 and"的隐式约定。
|
|
76
|
-
*
|
|
77
|
-
* @param {unknown} node 声明里的 `when`
|
|
78
|
-
* @param {object} [context] `{ ctx, standingMountFor }`:`preset` 原语需要它们(挂载期注入)
|
|
79
|
-
* @returns {Function|undefined} 谓词函数
|
|
80
|
-
*/
|
|
81
|
-
export function compileWhen(node, context = {}) {
|
|
82
|
-
if (node === undefined || node === null) return undefined
|
|
83
|
-
if (typeof node !== 'object' || Array.isArray(node)) {
|
|
84
|
-
throw new TypeError('trigger-spec: when must be an object (a composite node or a predicate node)')
|
|
85
|
-
}
|
|
86
|
-
const keys = Object.keys(node)
|
|
87
|
-
if (keys.length === 0) {
|
|
88
|
-
throw new TypeError('trigger-spec: when must not be an empty object — 空节点是「恒真」还是「写漏了」无法区分')
|
|
89
|
-
}
|
|
90
|
-
if (keys.length > 1) {
|
|
91
|
-
throw new TypeError(
|
|
92
|
-
`trigger-spec: when must declare exactly one key — got ${keys.sort().join(', ')}`
|
|
93
|
-
+ `(allowed: ${[...COMPOSITE_OPERATORS, ...Object.keys(PREDICATE_FACTORIES)].sort().join(', ')})`,
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
const [key] = keys
|
|
97
|
-
const value = node[key]
|
|
98
|
-
|
|
99
|
-
if (COMPOSITE_OPERATORS.includes(key)) {
|
|
100
|
-
if (key === 'not') {
|
|
101
|
-
return composite({ not: compileWhen(value, context) })
|
|
102
|
-
}
|
|
103
|
-
if (!Array.isArray(value) || value.length === 0) {
|
|
104
|
-
throw new TypeError(`trigger-spec: when.${key} must be a non-empty array of nodes`)
|
|
105
|
-
}
|
|
106
|
-
return composite({ [key]: value.map((child) => compileWhen(child, context)) })
|
|
17
|
+
/** 展开后的叶子必须是已知动作。 */
|
|
18
|
+
function assertActionKind(action, at) {
|
|
19
|
+
if (action === null || typeof action !== 'object' || Array.isArray(action)) {
|
|
20
|
+
throw new TypeError(`trigger-spec: ${at} must be an action declaration object`)
|
|
107
21
|
}
|
|
108
|
-
|
|
109
|
-
const factory = PREDICATE_FACTORIES[key]
|
|
110
|
-
if (factory === undefined) {
|
|
22
|
+
if (typeof action.kind !== 'string' || !Object.hasOwn(ACTION_KINDS, action.kind)) {
|
|
111
23
|
throw new TypeError(
|
|
112
|
-
`trigger-spec:
|
|
113
|
-
+ ` — known predicates: ${Object.keys(PREDICATE_FACTORIES).join(', ')}; composite: ${COMPOSITE_OPERATORS.join(', ')}`,
|
|
24
|
+
`trigger-spec: ${at}.kind must be one of ${Object.keys(ACTION_KINDS).join(', ')} — got ${JSON.stringify(action.kind)}`,
|
|
114
25
|
)
|
|
115
26
|
}
|
|
116
|
-
|
|
117
|
-
// `preset` 原语的取法需要挂载期注入(见 predicates.mjs 的三条硬约束),其余原语只用选项。
|
|
118
|
-
if (key === 'preset') {
|
|
119
|
-
return createPresetPredicate({ ...options, ctx: context.ctx, standingMountFor: context.standingMountFor })
|
|
120
|
-
}
|
|
121
|
-
return factory(options)
|
|
27
|
+
return action
|
|
122
28
|
}
|
|
123
29
|
|
|
124
|
-
/**
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
`trigger-spec: do[${index}].kind must be one of ${Object.keys(ACTION_KINDS).join(', ')} — got ${JSON.stringify(action.kind)}`,
|
|
135
|
-
)
|
|
136
|
-
}
|
|
137
|
-
return action
|
|
138
|
-
})
|
|
30
|
+
/**
|
|
31
|
+
* 声明级 `if` 与动作自身分支条件的合取;来自**声明级** `else` 的动作跳过声明级判定
|
|
32
|
+
* (它的条件里已含 `not(if)`)。两个条件缺省都表示无条件。
|
|
33
|
+
*/
|
|
34
|
+
function actionGate(declarationWhen, action) {
|
|
35
|
+
const own = action.actionWhen
|
|
36
|
+
const base = action.bypassRuleWhen === true ? undefined : declarationWhen
|
|
37
|
+
if (base === undefined) return own
|
|
38
|
+
if (own === undefined) return base
|
|
39
|
+
return subject => base(subject) === true && own(subject) === true
|
|
139
40
|
}
|
|
140
41
|
|
|
141
42
|
/**
|
|
@@ -161,9 +62,13 @@ export function compileDeclaration(spec, context = {}) {
|
|
|
161
62
|
if (typeof spec.channel !== 'string' || spec.channel.length === 0) {
|
|
162
63
|
throw new TypeError(`trigger-spec: trigger ${spec.id}: channel must be a non-empty event name`)
|
|
163
64
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
65
|
+
const label = `trigger-spec: trigger ${spec.id}`
|
|
66
|
+
// 旧名已按引擎重构退役:显式拒绝并给出新名。
|
|
67
|
+
if (spec.when !== undefined) throw new TypeError(`${label}: "when" 已退役,改用 "if"`)
|
|
68
|
+
if (spec.do !== undefined) throw new TypeError(`${label}: "do" 已退役,改用 "then"`)
|
|
69
|
+
const triggerIf = spec.if
|
|
70
|
+
const triggerThen = spec.then
|
|
71
|
+
if (triggerThen === undefined) throw new TypeError(`${label}: then is required`)
|
|
167
72
|
const channelOrder = spec.channelOrder ?? 0
|
|
168
73
|
if (!Number.isSafeInteger(channelOrder) || channelOrder < 0) {
|
|
169
74
|
throw new TypeError(`trigger-spec: trigger ${spec.id}: channelOrder must be a non-negative safe integer`)
|
|
@@ -172,11 +77,22 @@ export function compileDeclaration(spec, context = {}) {
|
|
|
172
77
|
if (!WATERFALL_POSITIONS.has(waterfallPosition)) {
|
|
173
78
|
throw new TypeError(`trigger-spec: trigger ${spec.id}: waterfallPosition must be one of ${[...WATERFALL_POSITIONS].join(', ')}`)
|
|
174
79
|
}
|
|
175
|
-
|
|
176
|
-
const
|
|
80
|
+
// 声明级 `if` 由注册侧判定;声明级 `else` 的动作自带 `not(if)` 并跳过它,否则自相矛盾。
|
|
81
|
+
const expanded = [
|
|
82
|
+
...expandActions(actionList(triggerThen, `${label}.then`), {}, `${label}.then`),
|
|
83
|
+
...(spec.else === undefined ? [] : expandActions(actionList(spec.else, `${label}.else`), {
|
|
84
|
+
outer: triggerIf === undefined ? [] : [{ not: triggerIf }],
|
|
85
|
+
bypass: true,
|
|
86
|
+
}, `${label}.else`)),
|
|
87
|
+
]
|
|
88
|
+
const when = compileWhen(triggerIf, context)
|
|
89
|
+
const actions = expanded.map(({ node, conditions, bypass }, index) => Object.assign(
|
|
90
|
+
{ ...assertActionKind(node, `action[${index}]`) },
|
|
91
|
+
{ actionWhen: compileWhen(conjunction(conditions), context), bypassRuleWhen: bypass },
|
|
92
|
+
))
|
|
177
93
|
// 保存期复用注册入口的纯准备阶段;不绑定 ctx,不创建预算或监听器。
|
|
178
94
|
for (const action of actions) prepareAction(action, {
|
|
179
|
-
when, promptConfigOptions: context.promptConfigOptions, ...registrationOptions({ waterfallPosition }),
|
|
95
|
+
when: action.actionWhen ?? when, promptConfigOptions: context.promptConfigOptions, ...registrationOptions({ waterfallPosition }),
|
|
180
96
|
})
|
|
181
97
|
const phase = spec.phase ?? actionExecutionPoint(actions[0]).phase
|
|
182
98
|
if (!ACTION_PHASES.includes(phase)) {
|
|
@@ -240,7 +156,7 @@ export function mountDeclarations(ctx, compiled, { plugin, warnOnce } = {}) {
|
|
|
240
156
|
plugin,
|
|
241
157
|
warnOnce,
|
|
242
158
|
promptConfigOptions: trigger.promptConfigOptions,
|
|
243
|
-
when: trigger.when,
|
|
159
|
+
when: actionGate(trigger.when, action),
|
|
244
160
|
prepend: trigger.waterfallPosition === 'outermost',
|
|
245
161
|
}))
|
|
246
162
|
}
|