dsh-plugin-prompt-tool 0.6.1 → 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.
- package/README.md +20 -11
- 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 +189 -79
- package/lib/index.mjs +1000 -356
- package/lib/preset-core.d.mts +1 -1
- package/lib/preset-core.mjs +29 -3
- package/lib/{prompt-configs-ThS4iXPg.mjs → prompt-configs-BnQKRHVb.mjs} +221 -108
- 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/lib/preset-core.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as mergePromptConfigs, i as loadPromptConfigFiles, n as PromptConfigFile, o as renderPromptConfigYaml, r as PromptConfigSpec, t as BuildCordisOptions } from "./prompt-configs-
|
|
1
|
+
import { a as mergePromptConfigs, i as loadPromptConfigFiles, n as PromptConfigFile, o as renderPromptConfigYaml, r as PromptConfigSpec, t as BuildCordisOptions } from "./prompt-configs-CN0sJTUL.mjs";
|
|
2
2
|
//#region src/preset-core.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* 渲染 anchored 组合文件:
|
package/lib/preset-core.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { h as loadPresetSpec, n as mergePromptConfigs, r as renderPromptConfigYaml, s as assertCompositionArray, t as loadPromptConfigFiles, x as renderComposition } from "./prompt-configs-BnQKRHVb.mjs";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
//#region src/preset-core.ts
|
|
4
4
|
/**
|
|
@@ -21,8 +21,9 @@ function buildCordis(prompt, options = {}) {
|
|
|
21
21
|
firstTurnText: typeof options.firstTurnText === "string" ? options.firstTurnText : "",
|
|
22
22
|
guideCustom: options.guideCustom === true,
|
|
23
23
|
guideText: typeof options.guideText === "string" ? options.guideText : "",
|
|
24
|
+
guideEnabled: typeof options.guideEnabled === "boolean" ? options.guideEnabled : void 0,
|
|
24
25
|
injectPrompt: options.injectPrompt !== false,
|
|
25
|
-
usePtcMode: options.usePtcMode
|
|
26
|
+
usePtcMode: typeof options.usePtcMode === "boolean" ? options.usePtcMode : void 0,
|
|
26
27
|
bootstrapMaxTokens: Number.isSafeInteger(options.bootstrapMaxTokens) && (options.bootstrapMaxTokens ?? 0) > 0 ? options.bootstrapMaxTokens : 0,
|
|
27
28
|
modelProvider: typeof options.modelProvider === "string" && options.modelProvider.length > 0 ? options.modelProvider : "",
|
|
28
29
|
modelName: typeof options.modelName === "string" && options.modelName.length > 0 ? options.modelName : "",
|
|
@@ -34,11 +35,36 @@ function buildCordis(prompt, options = {}) {
|
|
|
34
35
|
subagentReasoningEffort: typeof options.subagentReasoningEffort === "string" ? options.subagentReasoningEffort : "",
|
|
35
36
|
subagentTemperature: typeof options.subagentTemperature === "string" ? options.subagentTemperature : "",
|
|
36
37
|
subagentMaxTokens: typeof options.subagentMaxTokens === "string" ? options.subagentMaxTokens : "",
|
|
37
|
-
subagentPersona: typeof options.subagentPersona === "string" && options.subagentPersona.length > 0 ? options.subagentPersona : "",
|
|
38
38
|
toolFilterAllow: options.toolFilterAllow,
|
|
39
39
|
toolFilterDeny: options.toolFilterDeny,
|
|
40
40
|
maxDepth: options.maxDepth,
|
|
41
41
|
allowKinds: options.allowKinds,
|
|
42
|
+
promoteGate: options.promoteGate,
|
|
43
|
+
promoteAfterFirstResponse: options.promoteAfterFirstResponse,
|
|
44
|
+
maxPromoteSteps: options.maxPromoteSteps,
|
|
45
|
+
bootstrapTools: options.bootstrapTools,
|
|
46
|
+
compactionTools: options.compactionTools,
|
|
47
|
+
personaSectionsOnly: options.personaSectionsOnly,
|
|
48
|
+
workspaceLine: options.workspaceLine,
|
|
49
|
+
messageSources: options.messageSources,
|
|
50
|
+
deferredSources: options.deferredSources,
|
|
51
|
+
deferredGraceSteps: options.deferredGraceSteps,
|
|
52
|
+
instructionHint: options.instructionHint,
|
|
53
|
+
phase1FirstCallInstruction: options.phase1FirstCallInstruction,
|
|
54
|
+
stages: options.stages,
|
|
55
|
+
stagePreUnlock: options.stagePreUnlock,
|
|
56
|
+
stageAdvanceTool: options.stageAdvanceTool,
|
|
57
|
+
stageAdvanceDescription: options.stageAdvanceDescription,
|
|
58
|
+
stageSectionTemplate: options.stageSectionTemplate,
|
|
59
|
+
toolFilterSubagents: options.toolFilterSubagents,
|
|
60
|
+
anchorTurn: options.anchorTurn,
|
|
61
|
+
anchorTurnText: options.anchorTurnText,
|
|
62
|
+
deliberationGate: options.deliberationGate,
|
|
63
|
+
deliberationMinChars: options.deliberationMinChars,
|
|
64
|
+
deliberationMaxGatesPerTurn: options.deliberationMaxGatesPerTurn,
|
|
65
|
+
cotDrip: options.cotDrip,
|
|
66
|
+
cotDripEvery: options.cotDripEvery,
|
|
67
|
+
cotDripMaxPerTurn: options.cotDripMaxPerTurn,
|
|
42
68
|
firstTurnWord: typeof options.firstTurnWord === "string" && options.firstTurnWord.length > 0 ? options.firstTurnWord : void 0
|
|
43
69
|
};
|
|
44
70
|
const out = renderComposition(spec, runtime, ANCHORED_TEMPLATE_DIR);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { Pair, Scalar, YAMLMap, YAMLSeq, parse, parseDocument } from "yaml";
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
2
|
import { basename, dirname, join, resolve, sep } from "node:path";
|
|
4
3
|
import { spawn } from "node:child_process";
|
|
5
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { Pair, Scalar, YAMLMap, YAMLSeq, parse, parseDocument } from "yaml";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
//#region src/host/paths.ts
|
|
8
8
|
/** host 数据层的部署路径与序数常量(settings 层与运行时共用,避免 host→config 反向依赖)。 */
|
|
@@ -56,9 +56,10 @@ const DEFAULT_SKILLS_DIR = SKILLS_DIR;
|
|
|
56
56
|
* 一个预设 = 一个 preset.yml:
|
|
57
57
|
* - modules/params/content/meta 全部是直读参数,无模板语法;
|
|
58
58
|
* - 默认提示词配置由引擎按 params 生成(见 write-preset),promptConfigs 仅为可选覆盖;
|
|
59
|
-
* -
|
|
60
|
-
*
|
|
61
|
-
*
|
|
59
|
+
* - 组合模块的行级 config 由参数桥 buildModuleConfigsFromParams 按 params
|
|
60
|
+
* 构造对象合并(取代旧 __TOKEN__ 文本渲染,无占位符、无文本往返),
|
|
61
|
+
* params(UI/基础层)优先于 moduleConfigs 行级直写(旧作者锁定语义已移除)。
|
|
62
|
+
* 本模块负责参数归一化与引擎模块配置装配;所有 anchored 专属行为都在引擎内部。
|
|
62
63
|
*/
|
|
63
64
|
/** 包根 preset/ 目录(配置/模板文件夹):兼容源码运行(src/host)与打包运行(lib/)。 */
|
|
64
65
|
function packagePresetDir() {
|
|
@@ -78,12 +79,46 @@ function packageEngineDir() {
|
|
|
78
79
|
}
|
|
79
80
|
throw new Error("prompt-tool: cannot locate package engine/ directory");
|
|
80
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* preset.yml 读缓存:按 mtime+size 签名失效。load()/describe/param-overrides 等
|
|
84
|
+
* 每次请求读盘解析,加缓存后同一文件只解析一次;写盘路径(savePresetParams /
|
|
85
|
+
* withPresetDoc)与外部编辑(stat 签名变化)都会正确失效。
|
|
86
|
+
*/
|
|
87
|
+
const presetSpecCache = /* @__PURE__ */ new Map();
|
|
88
|
+
/** 写盘后失效缓存(调用方在写完 preset.yml 后调用;不调用也安全——stat 签名兜底)。 */
|
|
89
|
+
function invalidatePresetSpec(dir) {
|
|
90
|
+
presetSpecCache.delete(join(dir, "preset.yml"));
|
|
91
|
+
}
|
|
81
92
|
/** 加载某个预设模板的单一参数文件 preset/<name>/preset.yml。 */
|
|
82
93
|
function loadPresetSpec(dir) {
|
|
83
|
-
const
|
|
94
|
+
const file = join(dir, "preset.yml");
|
|
95
|
+
const stat = statSync(file);
|
|
96
|
+
const cached = presetSpecCache.get(file);
|
|
97
|
+
if (cached !== void 0 && cached.mtimeMs === stat.mtimeMs && cached.size === stat.size) return cached.spec;
|
|
98
|
+
const raw = readFileSync(file, "utf8");
|
|
84
99
|
const parsed = parse(raw, { logLevel: "silent" });
|
|
85
100
|
if (parsed === null || typeof parsed !== "object") throw new Error(`preset ${join(dir, "preset.yml")} is not a YAML map`);
|
|
86
101
|
if (typeof parsed.id !== "string" || parsed.id.length === 0) parsed.id = basename(dir);
|
|
102
|
+
const flattenModelGroup = (source, mapping) => {
|
|
103
|
+
if (source === null || typeof source !== "object" || Array.isArray(source)) return;
|
|
104
|
+
if (parsed.params === null || typeof parsed.params !== "object" || Array.isArray(parsed.params)) parsed.params = {};
|
|
105
|
+
for (const [segmentKey, flatKey] of Object.entries(mapping)) {
|
|
106
|
+
const value = source[segmentKey];
|
|
107
|
+
if (value !== void 0) parsed.params[flatKey] = value;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const flattenMapping = (segmentName) => {
|
|
111
|
+
const mapping = {};
|
|
112
|
+
for (const [flatKey, [segment, segmentKey]] of Object.entries(MODEL_SEGMENT_MAP)) if (segment === segmentName) mapping[segmentKey] = flatKey;
|
|
113
|
+
return mapping;
|
|
114
|
+
};
|
|
115
|
+
flattenModelGroup(parsed.model, flattenMapping("model"));
|
|
116
|
+
flattenModelGroup(parsed.subagentModel, flattenMapping("subagentModel"));
|
|
117
|
+
presetSpecCache.set(file, {
|
|
118
|
+
mtimeMs: stat.mtimeMs,
|
|
119
|
+
size: stat.size,
|
|
120
|
+
spec: parsed
|
|
121
|
+
});
|
|
87
122
|
return parsed;
|
|
88
123
|
}
|
|
89
124
|
/** 读取预设模板内容资产(presetText / agentsText);模板缺失时静默降级。
|
|
@@ -107,6 +142,23 @@ const asString = (value, fallback = "") => {
|
|
|
107
142
|
if (value === void 0 || value === null) return fallback;
|
|
108
143
|
return String(value);
|
|
109
144
|
};
|
|
145
|
+
/**
|
|
146
|
+
* 顶层模型段 ↔ 扁平参数键双向映射(单一来源)。
|
|
147
|
+
* loadPresetSpec 展平(段 → 扁平键)与 savePresetParams 迁移(扁平键 → 段)
|
|
148
|
+
* 共用本常量,杜绝两处字面量漂移。段结构 = 官方 agent-default-model 同构。
|
|
149
|
+
*/
|
|
150
|
+
const MODEL_SEGMENT_MAP = {
|
|
151
|
+
modelProvider: ["model", "provider"],
|
|
152
|
+
modelName: ["model", "name"],
|
|
153
|
+
modelReasoningEffort: ["model", "reasoningEffort"],
|
|
154
|
+
modelTemperature: ["model", "temperature"],
|
|
155
|
+
modelMaxTokens: ["model", "maxTokens"],
|
|
156
|
+
subagentModelProvider: ["subagentModel", "provider"],
|
|
157
|
+
subagentModelName: ["subagentModel", "name"],
|
|
158
|
+
subagentReasoningEffort: ["subagentModel", "reasoningEffort"],
|
|
159
|
+
subagentTemperature: ["subagentModel", "temperature"],
|
|
160
|
+
subagentMaxTokens: ["subagentModel", "maxTokens"]
|
|
161
|
+
};
|
|
110
162
|
/** 预设根:官方 USER_PRESET_DIR(~/.dsh/.agent-presets),导入/新建/种子化的预设都放这里。 */
|
|
111
163
|
function userPresetsDir() {
|
|
112
164
|
return DEFAULT_PRESET_DIR;
|
|
@@ -137,7 +189,7 @@ function resolvePresetDir(template) {
|
|
|
137
189
|
function listPresets() {
|
|
138
190
|
const scan = (dir) => {
|
|
139
191
|
try {
|
|
140
|
-
return readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).flatMap((entry) => {
|
|
192
|
+
return readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !entry.name.startsWith(".")).filter((entry) => entry.name !== "prompt-tool").flatMap((entry) => {
|
|
141
193
|
try {
|
|
142
194
|
const spec = loadPresetSpec(join(dir, entry.name));
|
|
143
195
|
if (typeof spec.id !== "string" || spec.id.length === 0) return [];
|
|
@@ -206,16 +258,13 @@ function ensurePresetSeed() {
|
|
|
206
258
|
const root = userPresetsDir();
|
|
207
259
|
const legacyMark = join(root, ".pt-seeded");
|
|
208
260
|
const state = readPluginState();
|
|
209
|
-
if (
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
} catch {}
|
|
217
|
-
return { created: [] };
|
|
218
|
-
}
|
|
261
|
+
if (existsSync(legacyMark)) try {
|
|
262
|
+
writePluginState({
|
|
263
|
+
...state,
|
|
264
|
+
seeded: true
|
|
265
|
+
});
|
|
266
|
+
rmSync(legacyMark, { force: true });
|
|
267
|
+
} catch {}
|
|
219
268
|
const created = [];
|
|
220
269
|
try {
|
|
221
270
|
mkdirSync(root, { recursive: true });
|
|
@@ -356,10 +405,18 @@ function openPresetLocation(id, presetRoot = userPresetsDir()) {
|
|
|
356
405
|
};
|
|
357
406
|
}
|
|
358
407
|
}
|
|
408
|
+
/** 删除 yaml 两级键;父集合缺失时不触发 deleteIn 对不存在集合的异常。 */
|
|
409
|
+
function deleteYamlPath(doc, path) {
|
|
410
|
+
if (doc.hasIn(path)) doc.deleteIn(path);
|
|
411
|
+
}
|
|
412
|
+
/** 删除扁平 params 键。 */
|
|
413
|
+
function deleteFlatParam(doc, key) {
|
|
414
|
+
deleteYamlPath(doc, ["params", key]);
|
|
415
|
+
}
|
|
359
416
|
/**
|
|
360
417
|
* 保存预设参数:写激活预设目录 preset.yml 的 params(merge)/ promptConfigs(整体替换)。
|
|
361
|
-
* parseDocument 保留注释与未知键(preset.yml
|
|
362
|
-
*
|
|
418
|
+
* parseDocument 保留注释与未知键(preset.yml 模板含大量注释);空值键删除('' / [],
|
|
419
|
+
* 回落模板/引擎默认;0 与 false 照常写入--语义与函数内注释、docs §3 一致)。写入后删除 prompt-tool.overrides.yml(旧参数覆盖
|
|
363
420
|
* 通道残留——参数已并入 preset.yml,避免旧值覆盖新值)。
|
|
364
421
|
*/
|
|
365
422
|
function savePresetParams(presetRoot, templateName, params, promptConfigs, variables, variablesEnabled) {
|
|
@@ -368,7 +425,14 @@ function savePresetParams(presetRoot, templateName, params, promptConfigs, varia
|
|
|
368
425
|
const doc = parseDocument(readFileSync(file, "utf8"), { logLevel: "silent" });
|
|
369
426
|
if (params !== void 0) for (const [key, value] of Object.entries(params)) {
|
|
370
427
|
if (value === void 0 || value === null || key.trim().length === 0) continue;
|
|
371
|
-
|
|
428
|
+
const isEmpty = value === "" || Array.isArray(value) && value.length === 0;
|
|
429
|
+
const segment = MODEL_SEGMENT_MAP[key];
|
|
430
|
+
if (segment !== void 0) {
|
|
431
|
+
if (isEmpty) deleteYamlPath(doc, [segment[0], segment[1]]);
|
|
432
|
+
else doc.setIn([segment[0], segment[1]], value);
|
|
433
|
+
deleteFlatParam(doc, key);
|
|
434
|
+
} else if (isEmpty) deleteFlatParam(doc, key);
|
|
435
|
+
else doc.setIn(["params", key], value);
|
|
372
436
|
}
|
|
373
437
|
if (promptConfigs !== void 0) {
|
|
374
438
|
const cleaned = promptConfigs.map((config) => {
|
|
@@ -389,7 +453,7 @@ function savePresetParams(presetRoot, templateName, params, promptConfigs, varia
|
|
|
389
453
|
else doc.deleteIn(["variables"]);
|
|
390
454
|
for (const [key, value] of Object.entries(variables)) {
|
|
391
455
|
if (typeof value !== "string") continue;
|
|
392
|
-
doc
|
|
456
|
+
deleteFlatParam(doc, key);
|
|
393
457
|
}
|
|
394
458
|
}
|
|
395
459
|
if (variablesEnabled !== void 0) {
|
|
@@ -397,8 +461,20 @@ function savePresetParams(presetRoot, templateName, params, promptConfigs, varia
|
|
|
397
461
|
else doc.setIn(["variablesEnabled"], false);
|
|
398
462
|
}
|
|
399
463
|
writeFileSync(file, doc.toString(), "utf8");
|
|
464
|
+
invalidatePresetSpec(join(presetRoot, templateName));
|
|
400
465
|
rmSync(join(presetRoot, templateName, "prompt-tool.overrides.yml"), { force: true });
|
|
401
466
|
}
|
|
467
|
+
/** 预设文件读-改-写(parseDocument 保留注释与未知键;mutate 内 setIn/deleteIn)。
|
|
468
|
+
* 角色卡库(characters)与世界书工具(world-book-tools)共用此入口,避免
|
|
469
|
+
* 各自实现 parseDocument 往返。 */
|
|
470
|
+
function withPresetDoc(presetDir, mutate) {
|
|
471
|
+
const file = join(presetDir, "preset.yml");
|
|
472
|
+
if (!existsSync(file)) throw new Error(`${presetDir} 无 preset.yml`);
|
|
473
|
+
const doc = parseDocument(readFileSync(file, "utf8"), { logLevel: "silent" });
|
|
474
|
+
mutate(doc);
|
|
475
|
+
writeFileSync(file, doc.toString(), "utf8");
|
|
476
|
+
invalidatePresetSpec(presetDir);
|
|
477
|
+
}
|
|
402
478
|
/** 删除预设目录(预设根/<id>;含同名导入的 .bak-* 备份目录)。
|
|
403
479
|
* 仅作用于预设根(官方 USER_PRESET_DIR),包内置模板天然不受影响;路径越界与非法 id 拒绝。
|
|
404
480
|
* 删除后宿主 agent-presets 目录列表自然不再出现该预设(官方 roster 即目录列表)。 */
|
|
@@ -454,17 +530,6 @@ function resolvePresetParams(spec, runtime) {
|
|
|
454
530
|
if (typeof params.promptText !== "string" || params.promptText.length === 0) params.promptText = typeof runtime.promptText === "string" ? runtime.promptText : "";
|
|
455
531
|
return params;
|
|
456
532
|
}
|
|
457
|
-
/** {{key}} 嵌套插值(块模板内引用 params);键正则与引擎插值及 processStText 中文变量支持一致。 */
|
|
458
|
-
function interpolateNested(text, scope) {
|
|
459
|
-
return text.replace(/\{\{([A-Za-z0-9_.\u4e00-\u9fff-]+)\}\}/g, (whole, key, offset) => {
|
|
460
|
-
if (!Object.prototype.hasOwnProperty.call(scope, key)) return whole;
|
|
461
|
-
const value = asString(scope[key]);
|
|
462
|
-
if (!value.includes("\n")) return value;
|
|
463
|
-
const lineStart = text.lastIndexOf("\n", offset) + 1;
|
|
464
|
-
const prefix = text.slice(lineStart, offset);
|
|
465
|
-
return value.split("\n").map((line, at) => at === 0 ? line : line.length > 0 ? prefix + line : "").join("\n");
|
|
466
|
-
});
|
|
467
|
-
}
|
|
468
533
|
/** 逗号分隔 / YAML flow 数组 / 空格分隔的字符串列表 → 字符串数组。 */
|
|
469
534
|
function parseListParam(value) {
|
|
470
535
|
if (Array.isArray(value)) return value.map((item) => String(item)).filter((item) => item.length > 0);
|
|
@@ -474,51 +539,95 @@ function parseListParam(value) {
|
|
|
474
539
|
return (trimmed.startsWith("[") && trimmed.endsWith("]") ? trimmed.slice(1, -1) : trimmed).split(",").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
475
540
|
}
|
|
476
541
|
/**
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
*
|
|
542
|
+
* 参数桥:params 扁平键 → 引擎模块行 config 对象(取代旧 __TOKEN__ 文本渲染)。
|
|
543
|
+
*
|
|
544
|
+
* 原则:
|
|
545
|
+
* - 未声明的键不合并(composition 行默认 / 引擎默认生效),与旧"空值删行"语义等价;
|
|
546
|
+
* - 值类型直达(布尔/数字/数组不再字符串化再解析);
|
|
547
|
+
* - 合并优先级:参数桥(UI/基础层)> moduleConfigs(模板/ST 行级直写)> 行默认。
|
|
480
548
|
* 模型路由/委派参数统一扁平键(modelProvider/subagentModelProvider/toolFilterAllow/maxDepth 等),
|
|
481
549
|
* 与官方 AgentOptions{provider,model} / toolFilter{allow,deny} / maxDepth 对齐。
|
|
482
550
|
*/
|
|
483
|
-
function
|
|
551
|
+
function buildModuleConfigsFromParams(params) {
|
|
552
|
+
const out = {};
|
|
553
|
+
const merge = (module, cfg) => {
|
|
554
|
+
if (Object.keys(cfg).length === 0) return;
|
|
555
|
+
out[module] = {
|
|
556
|
+
...out[module],
|
|
557
|
+
...cfg
|
|
558
|
+
};
|
|
559
|
+
};
|
|
560
|
+
const bootstrap = {};
|
|
561
|
+
if (typeof params.bootstrapMaxTokens === "number" && params.bootstrapMaxTokens > 0) bootstrap.bootstrapMaxTokens = params.bootstrapMaxTokens;
|
|
562
|
+
if (params.bootstrapTools !== void 0) bootstrap.bootstrapTools = parseListParam(params.bootstrapTools);
|
|
563
|
+
if (params.promoteGate !== void 0) bootstrap.promoteGate = params.promoteGate === true;
|
|
564
|
+
if (params.promoteAfterFirstResponse !== void 0) bootstrap.promoteAfterFirstResponse = params.promoteAfterFirstResponse === true;
|
|
565
|
+
if (params.maxPromoteSteps !== void 0 && Number.isSafeInteger(params.maxPromoteSteps)) bootstrap.maxPromoteSteps = params.maxPromoteSteps;
|
|
566
|
+
if (params.compactionTools !== void 0) bootstrap.compactionTools = parseListParam(params.compactionTools);
|
|
567
|
+
if (params.personaSectionsOnly !== void 0) bootstrap.personaSectionsOnly = params.personaSectionsOnly === true;
|
|
568
|
+
if (params.workspaceLine !== void 0) bootstrap.workspaceLine = params.workspaceLine === true;
|
|
569
|
+
if (typeof params.phase1FirstCallInstruction === "string" && params.phase1FirstCallInstruction.length > 0) bootstrap.phase1FirstCallInstruction = params.phase1FirstCallInstruction;
|
|
570
|
+
if (params.stages !== void 0) bootstrap.stages = params.stages;
|
|
571
|
+
if (params.stagePreUnlock !== void 0 && Number.isSafeInteger(params.stagePreUnlock)) bootstrap.stagePreUnlock = params.stagePreUnlock;
|
|
572
|
+
if (typeof params.stageAdvanceTool === "string" && params.stageAdvanceTool.length > 0) bootstrap.stageAdvanceTool = params.stageAdvanceTool;
|
|
573
|
+
if (typeof params.stageAdvanceDescription === "string" && params.stageAdvanceDescription.length > 0) bootstrap.stageAdvanceDescription = params.stageAdvanceDescription;
|
|
574
|
+
if (typeof params.stageSectionTemplate === "string" && params.stageSectionTemplate.length > 0) bootstrap.stageSectionTemplate = params.stageSectionTemplate;
|
|
575
|
+
merge("tool-bootstrap", bootstrap);
|
|
576
|
+
const gate = {};
|
|
577
|
+
if (params.allowKinds !== void 0) gate.allowKinds = parseListParam(params.allowKinds);
|
|
578
|
+
if (params.messageSources !== void 0) gate.messageSources = parseListParam(params.messageSources);
|
|
579
|
+
if (params.deferredSources !== void 0) gate.deferredSources = parseListParam(params.deferredSources);
|
|
580
|
+
if (params.deferredGraceSteps !== void 0 && Number.isSafeInteger(params.deferredGraceSteps)) gate.deferredGraceSteps = params.deferredGraceSteps;
|
|
581
|
+
if (params.instructionHint !== void 0) gate.instructionHint = params.instructionHint === true;
|
|
582
|
+
merge("context-gate", gate);
|
|
583
|
+
const presentation = {};
|
|
584
|
+
if (params.usePtcMode !== void 0) presentation.usePtcMode = params.usePtcMode === true;
|
|
585
|
+
merge("code-presentation", presentation);
|
|
586
|
+
const anchorTurn = {};
|
|
587
|
+
if (params.anchorTurn !== void 0) anchorTurn.enabled = params.anchorTurn === true;
|
|
588
|
+
if (typeof params.anchorTurnText === "string" && params.anchorTurnText.length > 0) anchorTurn.text = params.anchorTurnText;
|
|
589
|
+
merge("anchor-turn", anchorTurn);
|
|
590
|
+
const gate2 = {};
|
|
591
|
+
if (params.deliberationGate !== void 0) gate2.enabled = params.deliberationGate === true;
|
|
592
|
+
if (typeof params.deliberationMinChars === "number" && params.deliberationMinChars > 0) gate2.minChars = params.deliberationMinChars;
|
|
593
|
+
if (typeof params.deliberationMaxGatesPerTurn === "number" && params.deliberationMaxGatesPerTurn > 0) gate2.maxGatesPerTurn = params.deliberationMaxGatesPerTurn;
|
|
594
|
+
merge("deliberation-gate", gate2);
|
|
595
|
+
const drip = {};
|
|
596
|
+
if (params.cotDrip !== void 0) drip.enabled = params.cotDrip === true;
|
|
597
|
+
if (typeof params.cotDripEvery === "number" && params.cotDripEvery > 0) drip.every = params.cotDripEvery;
|
|
598
|
+
if (typeof params.cotDripMaxPerTurn === "number" && params.cotDripMaxPerTurn > 0) drip.maxPerTurn = params.cotDripMaxPerTurn;
|
|
599
|
+
merge("cot-drip", drip);
|
|
600
|
+
const editor = {};
|
|
601
|
+
editor.maxOutputChars = typeof params.strReplaceEditorMaxOutputChars === "number" && Number.isSafeInteger(params.strReplaceEditorMaxOutputChars) && params.strReplaceEditorMaxOutputChars > 0 ? params.strReplaceEditorMaxOutputChars : 16e3;
|
|
602
|
+
merge("str-replace-editor", editor);
|
|
603
|
+
const filter = {};
|
|
604
|
+
const mainAllow = parseListParam(params.toolFilterAllow);
|
|
605
|
+
const mainDeny = parseListParam(params.toolFilterDeny);
|
|
606
|
+
if (mainAllow.length > 0) filter.allow = mainAllow;
|
|
607
|
+
if (mainDeny.length > 0) filter.deny = mainDeny;
|
|
608
|
+
if (params.toolFilterSubagents === true) filter.includeSubagents = true;
|
|
609
|
+
merge("tool-filter", filter);
|
|
610
|
+
const subagent = {};
|
|
484
611
|
const provider = asString(params.subagentModelProvider, "");
|
|
485
612
|
const model = asString(params.subagentModelName, "");
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
613
|
+
if (provider.length > 0 && model.length > 0) subagent.agentOptions = {
|
|
614
|
+
provider,
|
|
615
|
+
model
|
|
616
|
+
};
|
|
617
|
+
const subAllow = parseListParam(params.toolFilterAllow);
|
|
618
|
+
const subDeny = parseListParam(params.toolFilterDeny);
|
|
619
|
+
if (subAllow.length > 0 || subDeny.length > 0) subagent.toolFilter = {
|
|
620
|
+
...subAllow.length > 0 ? { allow: subAllow } : {},
|
|
621
|
+
...subDeny.length > 0 ? { deny: subDeny } : {}
|
|
622
|
+
};
|
|
494
623
|
const rawMaxDepth = params.maxDepth;
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
if (
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
subagentLines.push("toolFilter:");
|
|
501
|
-
if (toolFilterAllow.length > 0) subagentLines.push(` allow: [${toolFilterAllow.join(", ")}]`);
|
|
502
|
-
if (toolFilterDeny.length > 0) subagentLines.push(` deny: [${toolFilterDeny.join(", ")}]`);
|
|
624
|
+
if (rawMaxDepth === "provider-managed") subagent.maxDepth = "provider-managed";
|
|
625
|
+
else if (Number.isSafeInteger(rawMaxDepth) && rawMaxDepth >= 0) subagent.maxDepth = rawMaxDepth;
|
|
626
|
+
if (Object.keys(subagent).length > 0) {
|
|
627
|
+
out["tool-subagent"] = subagent;
|
|
628
|
+
out["tool-subagent-fork"] = subagent;
|
|
503
629
|
}
|
|
504
|
-
|
|
505
|
-
const subagentConfigBlock = subagentLines.join("\n");
|
|
506
|
-
const bootstrap = typeof params.bootstrapMaxTokens === "number" && params.bootstrapMaxTokens > 0 ? `bootstrapMaxTokens: ${params.bootstrapMaxTokens}` : "";
|
|
507
|
-
const editorMaxOutputChars = typeof params.strReplaceEditorMaxOutputChars === "number" && Number.isSafeInteger(params.strReplaceEditorMaxOutputChars) && params.strReplaceEditorMaxOutputChars > 0 ? String(params.strReplaceEditorMaxOutputChars) : "16000";
|
|
508
|
-
return {
|
|
509
|
-
usePtcMode: params.usePtcMode === void 0 ? "" : params.usePtcMode === true ? "true" : "false",
|
|
510
|
-
bootstrapMaxTokens: bootstrap,
|
|
511
|
-
subagentConfig: subagentConfigBlock,
|
|
512
|
-
allowKinds: params.allowKinds === void 0 ? "" : Array.isArray(params.allowKinds) ? `[${params.allowKinds.map((item) => String(item)).join(", ")}]` : asString(params.allowKinds),
|
|
513
|
-
strReplaceEditorMaxOutputChars: editorMaxOutputChars,
|
|
514
|
-
mainToolFilterAllow: mainFilterAllowLine,
|
|
515
|
-
mainToolFilterDeny: mainFilterDenyLine,
|
|
516
|
-
mainToolFilterSubagents: String(mainFilterSubagents)
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
/** 预设 params + runtime → 组合 token 渲染(便捷入口)。 */
|
|
520
|
-
function resolvePresetTokens(spec, runtime) {
|
|
521
|
-
return renderEngineTokens(resolvePresetParams(spec, runtime));
|
|
630
|
+
return out;
|
|
522
631
|
}
|
|
523
632
|
/** 按参数文件的 modules 清单从引擎模块库装配组合文本。 */
|
|
524
633
|
/** 空模块清单兜底骨架(自定义预设空白起点:模块集与 minimal 一致,参数/配置全空)。 */
|
|
@@ -527,6 +636,7 @@ const FALLBACK_MODULES = [
|
|
|
527
636
|
"bootstrap-filesystem",
|
|
528
637
|
"context-gate",
|
|
529
638
|
"tool-bootstrap",
|
|
639
|
+
"code-presentation",
|
|
530
640
|
"prompt-config-engine",
|
|
531
641
|
"run-code-env",
|
|
532
642
|
"custom-bash",
|
|
@@ -550,9 +660,10 @@ function assembleModules(spec, library) {
|
|
|
550
660
|
* 2. 兼容 `composition:` 内联文本或组合清单名。
|
|
551
661
|
*/
|
|
552
662
|
/**
|
|
553
|
-
* 行级 config
|
|
554
|
-
* 数组型 config(如
|
|
555
|
-
* 未声明
|
|
663
|
+
* 行级 config 合并:仅支持 map 型 config 浅合并;
|
|
664
|
+
* 数组型 config(如 delegation 组)按子行 id 嵌套合并;未声明模块原样保留。
|
|
665
|
+
* 未声明 configs 时返回原文(零开销);parseDocument 往返保留注释。
|
|
666
|
+
* 本函数是参数桥产物落位组合行的唯一机制(含 delegation 组子行嵌套),不是预设覆盖通道。
|
|
556
667
|
*/
|
|
557
668
|
function applyModuleConfigs(raw, configs) {
|
|
558
669
|
if (configs === void 0 || Object.keys(configs).length === 0) return raw;
|
|
@@ -560,21 +671,38 @@ function applyModuleConfigs(raw, configs) {
|
|
|
560
671
|
if (!(doc.contents instanceof YAMLSeq)) return raw;
|
|
561
672
|
const rows = doc.contents;
|
|
562
673
|
let changed = false;
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
const idNode = item.get("id", true);
|
|
566
|
-
const id = idNode !== null && typeof idNode === "object" && "value" in idNode ? String(idNode.value) : void 0;
|
|
567
|
-
if (id === void 0 || !Object.prototype.hasOwnProperty.call(configs, id)) continue;
|
|
674
|
+
/** 把 cfg 的键写入一个 config 节点(无 config 时创建)。 */
|
|
675
|
+
const mergeInto = (item, cfg) => {
|
|
568
676
|
const existingConfig = item.get("config", true);
|
|
569
677
|
let configNode;
|
|
570
678
|
if (existingConfig instanceof YAMLMap) configNode = existingConfig;
|
|
571
679
|
else if (existingConfig === null || existingConfig === void 0) {
|
|
572
680
|
configNode = new YAMLMap();
|
|
573
681
|
item.items.push(new Pair(new Scalar("config"), configNode));
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
682
|
+
} else return false;
|
|
683
|
+
for (const [key, value] of Object.entries(cfg)) configNode.set(key, value);
|
|
684
|
+
return true;
|
|
685
|
+
};
|
|
686
|
+
/** 从行节点读 id(ParsedNode 值包装兼容)。 */
|
|
687
|
+
const rowId = (item) => {
|
|
688
|
+
const idNode = item.get("id", true);
|
|
689
|
+
return idNode !== null && typeof idNode === "object" && "value" in idNode ? String(idNode.value) : void 0;
|
|
690
|
+
};
|
|
691
|
+
for (const item of rows.items) {
|
|
692
|
+
if (!(item instanceof YAMLMap)) continue;
|
|
693
|
+
const id = rowId(item);
|
|
694
|
+
const existingConfig = item.get("config", true);
|
|
695
|
+
if (existingConfig instanceof YAMLSeq && id !== void 0 && !Object.prototype.hasOwnProperty.call(configs, id)) {
|
|
696
|
+
for (const child of existingConfig.items) {
|
|
697
|
+
if (!(child instanceof YAMLMap)) continue;
|
|
698
|
+
const childId = rowId(child);
|
|
699
|
+
if (childId === void 0 || !Object.prototype.hasOwnProperty.call(configs, childId)) continue;
|
|
700
|
+
if (mergeInto(child, configs[childId])) changed = true;
|
|
701
|
+
}
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
if (id === void 0 || !Object.prototype.hasOwnProperty.call(configs, id)) continue;
|
|
705
|
+
if (mergeInto(item, configs[id])) changed = true;
|
|
578
706
|
}
|
|
579
707
|
return changed ? doc.toString() : raw;
|
|
580
708
|
}
|
|
@@ -619,13 +747,18 @@ function loadCompositionText(spec, templateDir) {
|
|
|
619
747
|
return raw;
|
|
620
748
|
}
|
|
621
749
|
/**
|
|
622
|
-
*
|
|
623
|
-
*
|
|
624
|
-
* 如
|
|
750
|
+
* 预设组合渲染完整链路:模块装配 → 参数桥(moduleConfigs + params)行级合并。
|
|
751
|
+
* 合并优先级:参数桥(params/UI 基础层) > moduleConfigs(模板/ST 行级直写) > 行默认。
|
|
752
|
+
* moduleConfigs 仅补充参数桥未覆盖的行级 config(如 ST 导入的 tool-web.fetch),
|
|
753
|
+
* 不再锁定覆盖 UI 可管理参数(旧作者锁定语义已移除)。
|
|
625
754
|
*/
|
|
626
755
|
function renderComposition(spec, runtime, templateDir) {
|
|
627
|
-
const
|
|
628
|
-
|
|
756
|
+
const merged = buildModuleConfigsFromParams(resolvePresetParams(spec, runtime));
|
|
757
|
+
for (const [id, cfg] of Object.entries(spec.moduleConfigs ?? {})) merged[id] = {
|
|
758
|
+
...cfg,
|
|
759
|
+
...merged[id]
|
|
760
|
+
};
|
|
761
|
+
return applyModuleConfigs(loadCompositionText(spec, templateDir), merged);
|
|
629
762
|
}
|
|
630
763
|
/** 组合文本基础校验(模板无关):无未解析 token,且必须是 YAML 数组。 */
|
|
631
764
|
function assertCompositionArray(raw, spec) {
|
|
@@ -635,26 +768,6 @@ function assertCompositionArray(raw, spec) {
|
|
|
635
768
|
if (!Array.isArray(parsed)) throw new Error(`generated agent.cordis.yml is not a YAML array (preset ${spec.id})`);
|
|
636
769
|
return parsed;
|
|
637
770
|
}
|
|
638
|
-
/**
|
|
639
|
-
* 文本 token 替换:
|
|
640
|
-
* - token 独立成行时,替换块按该行缩进前缀(用于 line/block);
|
|
641
|
-
* - token 内联时直接替换(用于布尔/字符串标量)。
|
|
642
|
-
*/
|
|
643
|
-
function renderTemplateVariables(raw, variables) {
|
|
644
|
-
let text = raw.replace(/^[ \t]*(?:[A-Za-z0-9_.-]+:[ \t]*)?__([A-Za-z0-9_]+)__[ \t]*\r?\n/gm, (whole, key) => Object.prototype.hasOwnProperty.call(variables, key) && variables[key] === "" ? "" : whole);
|
|
645
|
-
return text.replace(/__([A-Za-z0-9_]+)__/g, (whole, key, offset) => {
|
|
646
|
-
if (!Object.prototype.hasOwnProperty.call(variables, key)) return whole;
|
|
647
|
-
const value = variables[key];
|
|
648
|
-
if (value === "") return "";
|
|
649
|
-
const lineStart = text.lastIndexOf("\n", offset) + 1;
|
|
650
|
-
const lineEndRaw = text.indexOf("\n", offset);
|
|
651
|
-
const lineEnd = lineEndRaw < 0 ? text.length : lineEndRaw;
|
|
652
|
-
const prefix = text.slice(lineStart, offset);
|
|
653
|
-
const rest = text.slice(offset + whole.length, lineEnd);
|
|
654
|
-
if (prefix.trim() === "" && rest.trim() === "") return value.split("\n").map((line, at) => at === 0 ? line : line.length > 0 ? prefix + line : "").join("\n");
|
|
655
|
-
return value;
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
771
|
//#endregion
|
|
659
772
|
//#region src/host/prompt-configs.ts
|
|
660
773
|
/**
|
|
@@ -768,4 +881,4 @@ function loadPromptConfigFiles(dir) {
|
|
|
768
881
|
return specs;
|
|
769
882
|
}
|
|
770
883
|
//#endregion
|
|
771
|
-
export {
|
|
884
|
+
export { DEFAULT_SKILLS_DIR as A, resolvePresetParams as C, writePluginState as D, withPresetDoc as E, LEGACY_USER_PRESETS_DIR as M, DEFAULT_PRESET_DIR as O, resolvePresetDir as S, userPresetsDir as T, packageEngineDir as _, applyModuleConfigs as a, removeUserPreset as b, buildModuleConfigsFromParams as c, ensurePresetSeed as d, listBuiltinTemplates as f, openPresetLocation as g, loadPresetSpec as h, MODEL_SEGMENT_MAP as i, LEGACY_CONTAINER_DIR as j, DEFAULT_RESIDENT_AGENTS_PATH as k, cloneBuiltinPreset as l, loadPresetContent as m, mergePromptConfigs as n, asString as o, listPresets as p, renderPromptConfigYaml as r, assertCompositionArray as s, loadPromptConfigFiles as t, duplicateUserPreset as u, parseImportedPresetId as v, savePresetParams as w, renderComposition as x, readPluginState as y };
|