dsh-plugin-prompt-tool 0.6.2 → 0.7.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 +11 -9
- package/engine/anchor-match.mjs +38 -12
- package/engine/anchor-turn.mjs +68 -0
- package/engine/classify-task.mjs +35 -0
- package/engine/code-presentation.mjs +103 -0
- package/engine/compositions/library/anchor-turn.yml +10 -0
- package/engine/compositions/library/bootstrap-filesystem.yml +1 -1
- package/engine/compositions/library/code-presentation.yml +8 -0
- package/engine/compositions/library/command-goal.yml +11 -0
- package/engine/compositions/library/compaction.yml +1 -1
- package/engine/compositions/library/context-gate.yml +1 -2
- package/engine/compositions/library/cot-drip.yml +11 -0
- package/engine/compositions/library/custom-bash.yml +1 -1
- package/engine/compositions/library/delegation.yml +11 -7
- package/engine/compositions/library/deliberation-gate.yml +11 -0
- package/engine/compositions/library/persistent-shell.yml +25 -2
- package/engine/compositions/library/persona.yml +6 -2
- package/engine/compositions/library/planning.yml +1 -1
- package/engine/compositions/library/prompt-config-engine.yml +1 -1
- package/engine/compositions/library/run-code-env.yml +1 -1
- package/engine/compositions/library/skill-filesystem.yml +1 -1
- package/engine/compositions/library/skill-search.yml +1 -1
- package/engine/compositions/library/str-replace-editor.yml +2 -2
- package/engine/compositions/library/tool-ask-user.yml +1 -1
- package/engine/compositions/library/tool-bash.yml +1 -1
- package/engine/compositions/library/tool-bootstrap.yml +1 -3
- package/engine/compositions/library/tool-config-engine.yml +9 -0
- package/engine/compositions/library/tool-filter.yml +3 -7
- package/engine/compositions/library/tool-fs-search.yml +1 -1
- package/engine/compositions/library/tool-fs.yml +1 -1
- package/engine/compositions/library/tool-goal.yml +1 -9
- package/engine/compositions/library/tool-jobs.yml +1 -1
- package/engine/compositions/library/tool-pwsh.yml +1 -1
- package/engine/compositions/library/tool-todo.yml +1 -1
- package/engine/compositions/library/tool-web.yml +2 -2
- package/engine/compositions/source/local/code-presentation.yml +8 -0
- package/engine/compositions/source/local/context-gate.yml +0 -1
- package/engine/compositions/source/local/str-replace-editor.yml +10 -0
- package/engine/compositions/source/local/tool-bootstrap.yml +1 -3
- package/engine/compositions/source/local/tool-config-engine.yml +9 -0
- package/engine/compositions/source/local/tool-filter.yml +8 -0
- package/engine/cot-drip.mjs +137 -0
- package/engine/custom-bash.mjs +73 -21
- package/engine/deliberation-gate.mjs +127 -0
- package/engine/layers.mjs +223 -198
- package/engine/run-code-env.mjs +8 -2
- package/engine/schema.mjs +1 -1
- package/engine/strategies.mjs +25 -14
- package/engine/tool-bootstrap.mjs +185 -59
- package/engine/tool-config-engine.mjs +390 -0
- package/lib/client.js +3840 -2311
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +186 -101
- package/lib/index.mjs +1012 -413
- package/lib/preset-core.d.mts +1 -1
- package/lib/preset-core.mjs +29 -3
- package/lib/{prompt-configs-BgFw_bFf.mjs → prompt-configs-BnQKRHVb.mjs} +211 -136
- package/lib/prompt-configs-CN0sJTUL.d.mts +193 -0
- package/package.json +121 -105
- package/preset/anchored/preset.yml +262 -308
- package/preset/creative/preset.yml +34 -32
- package/preset/custom/preset.yml +0 -1
- package/preset/liangshen/preset.yml +53 -50
- package/preset/minimal/preset.yml +18 -17
- package/preset/ptc/preset.yml +35 -33
- package/preset/standard/preset.yml +34 -32
- package/templates/10-pre-step.yml +18 -15
- package/templates/14-first-turn-anchor.yml +13 -13
- package/templates/15-guide-auto.yml +13 -13
- package/templates/16-custom-fallback.yml +19 -18
- package/templates/18-placeholder-env-facts.yml +13 -2
- package/templates/30-runtime-context.yml +3 -0
- package/templates/40-agent-request.yml +9 -9
- package/templates/60-tool-pipeline.yml +9 -8
- package/templates/tools/10-shell-command.yml +20 -0
- package/templates/tools/20-http-fetch.yml +24 -0
- package/templates/tools/30-fs-read.yml +20 -0
- package/templates/tools/40-delegate-character.yml +15 -0
- package/templates/tools/50-delegate-worldbook.yml +15 -0
- package/templates/tools/60-delegate-session-var.yml +15 -0
- package/templates/tools/70-delegate-worldbook-upsert.yml +36 -0
- package/lib/prompt-configs-B4vH09wx.d.mts +0 -100
- package/templates/11-merged-a.yml +0 -11
- package/templates/13-anchor.yml +0 -19
- package/templates/17-instruction-hint.yml +0 -23
- package/templates/19-placeholder-skill-catalog.yml +0 -19
- 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` 常驻 /
|
|
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
|
-
| `
|
|
42
|
-
| `
|
|
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
|
|
51
|
-
| 引导 | `guideCustom` `guideText` `
|
|
50
|
+
| 锚定 | `firstTurnAnchor` `firstTurnCustom` `firstTurnText` `firstTurnWord`(空 = 自动从锚句派生确认词)`firstTurnBuild` `firstTurnInspect` `firstTurnDeep` |
|
|
51
|
+
| 引导 | `guideCustom` `guideText` `guideWeak` `guideDeep`(复杂判定 fallback 复用锚定的 `complexPattern`) |
|
|
52
52
|
| PTC/门控 | `usePtcMode` `bootstrapMaxTokens` `injectPrompt` `allowKinds` |
|
|
53
|
-
| 人设 |
|
|
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
|
|
116
|
+
- **匹配选项**:`caseSensitive` / `wholeWords`;正则形态键(`/regex/` 或含特殊字符)自动检测
|
|
115
117
|
- **管理**:模块列表顶部下拉选「世界书」过滤(完整模块卡片编辑 + 批量启用/禁用);
|
|
116
118
|
模型工具 `world_book_list/upsert/delete`(`note` 写入角色卡记忆)
|
|
117
119
|
- **ST 变量**:`setvar`/`getvar` 收集进顶层 `variables`、未定义自定义宏自动登记空值占位;
|
package/engine/anchor-match.mjs
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
*
|
|
13
13
|
* 模式:
|
|
14
14
|
* scan = 全文扫描(world-book 消息批匹配);
|
|
15
|
-
* prefix = 文本开头匹配(custom-fallback 首轮 reasoning
|
|
16
|
-
*
|
|
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
|
-
/**
|
|
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 =
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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,6 +1,6 @@
|
|
|
1
1
|
# module: delegation
|
|
2
|
-
# source:
|
|
3
|
-
# local patches:
|
|
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.
|
|
51
|
-
#
|
|
52
|
-
#
|
|
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:
|
|
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
|
|
3
|
-
#
|
|
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:
|
|
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:
|
|
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: skill-filesystem
|
|
2
|
-
# source:
|
|
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: str-replace-editor
|
|
2
|
-
# source:
|
|
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:
|
|
10
|
+
maxOutputChars: 16000
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# module: tool-ask-user
|
|
2
|
-
# source:
|
|
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:
|
|
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 ───────────────────────────────────────────────────────────────────
|