dsh-paoding 0.3.7 → 0.3.9
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 +4 -3
- package/README_en.md +4 -3
- package/docs/configuration.md +36 -2
- package/docs/configuration_en.md +36 -2
- package/docs/installation.md +2 -2
- package/docs/installation_en.md +2 -2
- package/docs/orchestration.md +20 -1
- package/docs/orchestration_en.md +20 -1
- package/package.json +1 -1
- package/plugins/paoding-config-ui/index.mjs +29 -5
- package/plugins/paoding-config-ui/lib/client.js +139 -13
- package/plugins/paoding-config-ui/package.json +1 -1
- package/presets/orchestrator/agent.cordis.yml +7 -1
- package/tools/lib/alloc.mjs +16 -8
- package/tools/lib/compose.mjs +108 -20
- package/tools/lib/config.mjs +37 -7
- package/tools/lib/upgrade.mjs +73 -26
|
@@ -114,8 +114,11 @@ window.__ModuleLoader__.load({
|
|
|
114
114
|
return Icon ? h(Icon, { size: size }) : null;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
// 降级 / 报错提示行。role 可选:缺省时沿用旧口径(error 行 alert 强提醒,
|
|
118
|
+
// warn 行不带 role 走低调展示);调用方显式传 "status" 则礼貌播报一次,
|
|
119
|
+
// 供「拉取失败但仍可用」这类降级提示用(不抢屏,读屏不打断)。
|
|
120
|
+
function statusRow(cls, iconNode, text, role) {
|
|
121
|
+
return h("div", { className: cls, role: role || (cls === "omd-statusError" ? "alert" : undefined) },
|
|
119
122
|
iconNode ? h("span", { className: "omd-statusIcon" }, iconNode) : null,
|
|
120
123
|
h("span", { className: "omd-statusText" }, text));
|
|
121
124
|
}
|
|
@@ -193,6 +196,27 @@ window.__ModuleLoader__.load({
|
|
|
193
196
|
"PERSISTENCE_UNAVAILABLE:需在 ~/.dsh/cordis.patch.yml 挂 " +
|
|
194
197
|
"@deepseek-ai/dsh-session-persistence-jsonl(host 层、机器级改动,详见 docs/orchestration.md)。";
|
|
195
198
|
|
|
199
|
+
// ── 启动方式(roles.<toolName>.start_mode)─────────────────────────────
|
|
200
|
+
// 定稿键名 'fresh' | 'fork',缺省 fresh。与后端序列化形状一致:config 层
|
|
201
|
+
// normalizeStartMode 恒收成这两个字面量(缺省/非法回落 'fresh',落盘恒写出),
|
|
202
|
+
// assignments 与回填照搬同款取值。注意与 roles.<toolName>.provider(LLM 路由)
|
|
203
|
+
// 无关 —— 本键只决定委派块的块级 provider 行(spawn / fork)。
|
|
204
|
+
var ROLE_SM_FORK = "fork";
|
|
205
|
+
var ROLE_SM_FRESH = "fresh";
|
|
206
|
+
|
|
207
|
+
// 角色条目 start_mode 透传归一:恰好等于 'fork' 才认,其余(缺省 / null /
|
|
208
|
+
// 手编误值)一律 'fresh'(与 normalizeStartMode 同口径)。
|
|
209
|
+
function roleStartModeOf(baseRoles, n) {
|
|
210
|
+
var r = (baseRoles || {})[n];
|
|
211
|
+
return r && r.start_mode === ROLE_SM_FORK ? ROLE_SM_FORK : ROLE_SM_FRESH;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 「继承对话(fork)」选中且该角色配了专用模型时的行内提示(定稿文案):
|
|
215
|
+
// fork 子代理继承主 agent 的提供方与模型,专用模型不生效。
|
|
216
|
+
var ROLE_SM_FORK_MODEL_HINT =
|
|
217
|
+
"继承对话的子代理随主 agent 的当前模型启动,上方专用模型不会生效;" +
|
|
218
|
+
"应用时会忽略该项模型配置。";
|
|
219
|
+
|
|
196
220
|
|
|
197
221
|
// mcp__ 前缀判定(归「MCP 工具」组的依据,供角色工具网格分组与
|
|
198
222
|
// customCoreToolsOf 使用;只做展示分组,不影响识别/分配)。非 mcp__ 名字
|
|
@@ -235,7 +259,8 @@ window.__ModuleLoader__.load({
|
|
|
235
259
|
|
|
236
260
|
// 版本提示(渲染在页头标题旁,由 PageShell 持有):常态版本号不进正文;
|
|
237
261
|
// updateAvailable 时这里渲染醒目提示卡:releaseUrl 新标签页打开 release 页、
|
|
238
|
-
// 「升级」按钮走 onUpgrade
|
|
262
|
+
// 「升级」按钮走 onUpgrade(一键插件通道自升级,通道按 profile 由服务端
|
|
263
|
+
// 分流),并保留当前版本号。
|
|
239
264
|
// latest 为 null 一律不显示新版部分;检测失败(error 非空)改渲染弱化失败行
|
|
240
265
|
// (⚠ 版本检测失败 · 重试,完整原因在 title 悬浮提示),不再整行静默。
|
|
241
266
|
// opts(可省):busy/busyOp 复用面板级互斥(任何操作进行中都禁用升级,
|
|
@@ -717,6 +742,7 @@ window.__ModuleLoader__.load({
|
|
|
717
742
|
var _swr = useState(0), switchRev = _swr[0], setSwitchRev = _swr[1];
|
|
718
743
|
var _wsl = useState([]), wsList = _wsl[0], setWsList = _wsl[1]; // 宿主工作区列表(GET /api/paoding/workspaces;失败降级为空数组,pill 由配置文件键兜底)
|
|
719
744
|
var _wslt = useState(false), wsListTried = _wslt[0], setWsListTried = _wslt[1]; // 列表请求尘埃落定标记(成败均置位):pendingOpenWs 消费条件用
|
|
745
|
+
var _wsle = useState(""), wsListErr = _wsle[0], setWsListErr = _wsle[1]; // 列表拉取失败的降级提示("" = 正常零占位):标签条只剩配置文件兜底的工作区时,给用户一句交代
|
|
720
746
|
var _wsao = useState(false), wsAddOpen = _wsao[0], setWsAddOpen = _wsao[1]; // 「添加工作区」弹窗开合态(旧版是 tab 条下方的内联展开行)
|
|
721
747
|
var _wsap = useState(""), wsAddPath = _wsap[0], setWsAddPath = _wsap[1];
|
|
722
748
|
var _wsae = useState(""), wsAddErr = _wsae[0], setWsAddErr = _wsae[1];
|
|
@@ -724,6 +750,7 @@ window.__ModuleLoader__.load({
|
|
|
724
750
|
var _ran = useState(""), roleAddName = _ran[0], setRoleAddName = _ran[1];
|
|
725
751
|
var _radn = useState(""), roleAddDispName = _radn[0], setRoleAddDispName = _radn[1]; // 弹窗第二字段「显示名」(可选;残值语义同 roleAddName,成功提交才清)
|
|
726
752
|
var _rabm = useState("one-shot"), roleAddBgMode = _rabm[0], setRoleAddBgMode = _rabm[1]; // 弹窗第三字段「会话模式」:'one-shot' | 'continuable'(残值语义同上,成功提交才复位)
|
|
753
|
+
var _rasm = useState("fresh"), roleAddStartMode = _rasm[0], setRoleAddStartMode = _rasm[1]; // 弹窗第四字段「启动方式」:'fresh' | 'fork'(残值语义同上,成功提交才复位)
|
|
727
754
|
var _rae = useState(""), roleAddErr = _rae[0], setRoleAddErr = _rae[1];
|
|
728
755
|
// 「重命名自定义角色」弹窗三件套(原原生 prompt 改模态框):For 为
|
|
729
756
|
// null = 关闭,非空 = 待改名的旧 toolName(身份键,提交时迁移 skills 引用)。
|
|
@@ -808,6 +835,9 @@ window.__ModuleLoader__.load({
|
|
|
808
835
|
// 会话模式透传:仅 'continuable' 认可,其余归 'one-shot'(字面量,
|
|
809
836
|
// 与 config 层 normalizeBackgroundMode 的序列化形状一致)
|
|
810
837
|
background_mode: roleBgModeOf(base.roles, name),
|
|
838
|
+
// 启动方式透传:仅 'fork' 认可,其余归 'fresh'(与 config 层
|
|
839
|
+
// normalizeStartMode 的序列化形状一致;决定委派块块级 provider 行)
|
|
840
|
+
start_mode: roleStartModeOf(base.roles, name),
|
|
811
841
|
tools: (base.roles && base.roles[name] && base.roles[name].tools) ||
|
|
812
842
|
(d.blocks && d.blocks[name]) || [],
|
|
813
843
|
};
|
|
@@ -822,6 +852,8 @@ window.__ModuleLoader__.load({
|
|
|
822
852
|
provider: roleStringRef(base.roles, name, "provider"),
|
|
823
853
|
// 会话模式与内置同款收法:'one-shot' = 缺省一次性,'continuable' = 可续
|
|
824
854
|
background_mode: roleBgModeOf(base.roles, name),
|
|
855
|
+
// 启动方式与内置同款收法:'fresh' = 缺省全新启动,'fork' = 继承对话
|
|
856
|
+
start_mode: roleStartModeOf(base.roles, name),
|
|
825
857
|
tools: base.roles[name].tools || [],
|
|
826
858
|
};
|
|
827
859
|
});
|
|
@@ -852,15 +884,22 @@ window.__ModuleLoader__.load({
|
|
|
852
884
|
|
|
853
885
|
// 工作区列表:面板加载时拉一次宿主注册表(与 state 并行)。失败降级为
|
|
854
886
|
// 空列表——workspaceRowsOf 会用 state.existing.workspaces 的键兜底出 pill,
|
|
855
|
-
//
|
|
887
|
+
// 绝不阻塞面板。降级不再无声:宿主侧故障(如插件实例已 disposed 的僵尸
|
|
888
|
+
// 场景)会让接口 500,标签条只剩配置文件兜底的 tab,用户容易误判成
|
|
889
|
+
// 「功能坏了」,故留一行可见提示;err.message 截短后括注原文,便于对照
|
|
890
|
+
// 日志定位。请求错误 / 响应格式异常都汇入同一个 catch,提示口径一致。
|
|
856
891
|
var loadWorkspaces = useCallback(function () {
|
|
857
892
|
api("workspaces").then(function (d) {
|
|
858
893
|
if (!d || d.ok !== true || !Array.isArray(d.items)) throw new Error("工作区列表响应格式异常");
|
|
859
894
|
setWsList(d.items);
|
|
860
895
|
setWsListTried(true);
|
|
861
|
-
|
|
896
|
+
setWsListErr("");
|
|
897
|
+
}).catch(function (err) {
|
|
862
898
|
setWsList([]); // 静默降级:只用配置文件里已有的工作区键
|
|
863
899
|
setWsListTried(true);
|
|
900
|
+
var msg = err && err.message ? String(err.message) : "";
|
|
901
|
+
setWsListErr("宿主工作区列表拉取失败,仅显示配置文件中的工作区;重启 DSH 后通常可恢复"
|
|
902
|
+
+ (msg ? "(" + (msg.length > 80 ? msg.slice(0, 80) + "…" : msg) + ")" : ""));
|
|
864
903
|
});
|
|
865
904
|
}, [api]);
|
|
866
905
|
|
|
@@ -1246,13 +1285,15 @@ window.__ModuleLoader__.load({
|
|
|
1246
1285
|
var next = JSON.parse(JSON.stringify(prev));
|
|
1247
1286
|
// 新角色全字段出厂形状:与 buildAssignments / restoreBuiltinRole 条目一致
|
|
1248
1287
|
//(model/provider 置 null = 跟随主 agent 当前模型;background_mode
|
|
1249
|
-
// 用弹窗单选值,字面量 'one-shot' | 'continuable'
|
|
1250
|
-
//
|
|
1288
|
+
// 用弹窗单选值,字面量 'one-shot' | 'continuable';start_mode 用弹窗
|
|
1289
|
+
// 单选值,字面量 'fresh' | 'fork',决定委派块块级 provider 行)。name
|
|
1290
|
+
// 是可选显示名(null = 用 toolName 当标题),不再恒 null。
|
|
1251
1291
|
next.roles[name] = {
|
|
1252
1292
|
persona: null,
|
|
1253
1293
|
name: disp,
|
|
1254
1294
|
model: null,
|
|
1255
1295
|
provider: null,
|
|
1296
|
+
start_mode: roleAddStartMode,
|
|
1256
1297
|
background_mode: roleAddBgMode,
|
|
1257
1298
|
// 出厂 tools 默认全选 = 核心工具面(customCoreToolsOf:restrictBase
|
|
1258
1299
|
// 去四个委派名与 mcp__ 工具)+ host 检测库存。两集合不相交,无需去重
|
|
@@ -1265,6 +1306,7 @@ window.__ModuleLoader__.load({
|
|
|
1265
1306
|
setRoleAddName("");
|
|
1266
1307
|
setRoleAddDispName("");
|
|
1267
1308
|
setRoleAddBgMode("one-shot"); // 成功提交即复位出厂默认(取消重开才保留残值)
|
|
1309
|
+
setRoleAddStartMode("fresh"); // 成功提交即复位出厂默认(取消重开才保留残值)
|
|
1268
1310
|
setRoleAddErr("");
|
|
1269
1311
|
toast.ok('已新建角色 "' + name + '",记得「保存并应用」');
|
|
1270
1312
|
}
|
|
@@ -1373,13 +1415,14 @@ window.__ModuleLoader__.load({
|
|
|
1373
1415
|
// (data.blocks[name]),不沿用删前自定义配置——恢复即出厂默认,简化处理。
|
|
1374
1416
|
// 显示名同样置 null(出厂默认),重建条目与 buildAssignments 形状一致。
|
|
1375
1417
|
// 专用模型 / provider 同理置 null:恢复 = 回到「跟随主 agent 当前模型」,
|
|
1376
|
-
// 不保留删前的模型固定配置。
|
|
1418
|
+
// 不保留删前的模型固定配置。start_mode 置 'fresh'、background_mode 置
|
|
1419
|
+
// 'one-shot'(出厂缺省)。
|
|
1377
1420
|
function restoreBuiltinRole(name) {
|
|
1378
1421
|
setAssign(function (prev) {
|
|
1379
1422
|
var next = JSON.parse(JSON.stringify(prev));
|
|
1380
1423
|
next.roles_remove = (next.roles_remove || []).filter(function (r) { return r !== name; });
|
|
1381
1424
|
var defTools = (data && data.blocks && data.blocks[name]) || [];
|
|
1382
|
-
next.roles[name] = { persona: null, name: null, model: null, provider: null, background_mode: "one-shot", tools: defTools.slice() };
|
|
1425
|
+
next.roles[name] = { persona: null, name: null, model: null, provider: null, start_mode: "fresh", background_mode: "one-shot", tools: defTools.slice() };
|
|
1383
1426
|
return next;
|
|
1384
1427
|
});
|
|
1385
1428
|
}
|
|
@@ -1775,9 +1818,35 @@ window.__ModuleLoader__.load({
|
|
|
1775
1818
|
roleAddBgMode === "continuable" && data && data.persistenceAvailable === false
|
|
1776
1819
|
? statusRow("omd-statusWarn", ic(P.IconWarningOutline16, 16), ROLE_BG_PERSISTENCE_WARN)
|
|
1777
1820
|
: null,
|
|
1821
|
+
// 「启动方式」单选(与角色卡 roleStartModeBlock 同款语义):缺省全新,
|
|
1822
|
+
// 选「继承对话」才写 start_mode: 'fork'(委派块块级 provider 行)。
|
|
1823
|
+
h("label", { className: "pd-modalLabel" }, "启动方式"),
|
|
1824
|
+
h("div", { className: "omd-nameRow" },
|
|
1825
|
+
h("label", { className: "omd-toolItem" },
|
|
1826
|
+
h("input", {
|
|
1827
|
+
type: "radio",
|
|
1828
|
+
className: "omd-check",
|
|
1829
|
+
name: "pd-sm-roleadd",
|
|
1830
|
+
checked: roleAddStartMode !== "fork",
|
|
1831
|
+
onChange: function () { setRoleAddStartMode("fresh"); },
|
|
1832
|
+
}),
|
|
1833
|
+
h("span", { className: "omd-toolName" }, "全新(fresh)")),
|
|
1834
|
+
h("label", { className: "omd-toolItem" },
|
|
1835
|
+
h("input", {
|
|
1836
|
+
type: "radio",
|
|
1837
|
+
className: "omd-check",
|
|
1838
|
+
name: "pd-sm-roleadd",
|
|
1839
|
+
checked: roleAddStartMode === "fork",
|
|
1840
|
+
onChange: function () { setRoleAddStartMode("fork"); },
|
|
1841
|
+
}),
|
|
1842
|
+
h("span", { className: "omd-toolName" }, "继承对话(fork)"))),
|
|
1843
|
+
roleAddStartMode === "fork"
|
|
1844
|
+
? h("div", { className: "omd-hint" },
|
|
1845
|
+
"继承对话的子代理以主 agent 已完成的对话轮次为初始内容启动(一次性快照,之后两边各自推进);工具面仍以本角色配置为准。")
|
|
1846
|
+
: null,
|
|
1778
1847
|
roleAddErr ? statusRow("omd-statusError", ic(P.IconWarningOutline16, 16), roleAddErr) : null,
|
|
1779
1848
|
h("div", { className: "omd-hint" },
|
|
1780
|
-
"角色名须为 2-32 位小写字母/数字/下划线/连字符,小写字母开头;内置名不可新建。显示名可选,不能换行,trim 后最多 60 字符,留空用 toolName 当标题。新角色工具面默认放开全部检测到的工具,可在卡片里再收窄。会话模式缺省一次性(one-shot
|
|
1849
|
+
"角色名须为 2-32 位小写字母/数字/下划线/连字符,小写字母开头;内置名不可新建。显示名可选,不能换行,trim 后最多 60 字符,留空用 toolName 当标题。新角色工具面默认放开全部检测到的工具,可在卡片里再收窄。会话模式缺省一次性(one-shot),选「可续」后仍可在角色卡里改。启动方式缺省全新(fresh),选「继承对话」后仍可在角色卡里改。")),
|
|
1781
1850
|
h("div", { className: "pd-modalFooter" },
|
|
1782
1851
|
h(P.Button, { variant: "outline", size: "md", onClick: closeRoleAddModal }, "取消"),
|
|
1783
1852
|
h(P.Button, {
|
|
@@ -2231,6 +2300,50 @@ window.__ModuleLoader__.load({
|
|
|
2231
2300
|
: null);
|
|
2232
2301
|
}
|
|
2233
2302
|
|
|
2303
|
+
// 角色「启动方式」行(内置与自定义角色通用,同 roleBgModeBlock 的定位):
|
|
2304
|
+
// 单选 roles.<toolName>.start_mode ——「全新(fresh)」为缺省(字面量
|
|
2305
|
+
// 'fresh',与 config 层 normalizeStartMode 恒收两个合法值的序列化形状
|
|
2306
|
+
// 一致),「继承对话(fork)」写 'fork'(委派块的块级 provider 行改落
|
|
2307
|
+
// fork)。选中继承对话且该角色配了专用模型时行内提示互斥:fork 子代理
|
|
2308
|
+
// 继承主 agent 的提供方与模型,专用模型不生效(应用时后端 warn 并忽略)。
|
|
2309
|
+
// 注意与「专用模型」行的 provider 字段(LLM 路由)无关。
|
|
2310
|
+
function roleStartModeBlock(name) {
|
|
2311
|
+
var role = assign.roles[name] || {};
|
|
2312
|
+
var fork = role.start_mode === "fork";
|
|
2313
|
+
var hasModel = typeof role.model === "string" && role.model !== "";
|
|
2314
|
+
function commitStartMode(toFork) {
|
|
2315
|
+
setAssign(function (prev) {
|
|
2316
|
+
var next = JSON.parse(JSON.stringify(prev));
|
|
2317
|
+
next.roles[name].start_mode = toFork ? "fork" : "fresh";
|
|
2318
|
+
return next;
|
|
2319
|
+
});
|
|
2320
|
+
}
|
|
2321
|
+
function smOption(key, label, checked, on) {
|
|
2322
|
+
return h("label", { key: key, className: "omd-toolItem" },
|
|
2323
|
+
h("input", {
|
|
2324
|
+
type: "radio",
|
|
2325
|
+
className: "omd-check",
|
|
2326
|
+
name: "pd-sm-" + name, // 每角色独立单选组;name 含 toolName 不串台
|
|
2327
|
+
checked: checked,
|
|
2328
|
+
disabled: busy,
|
|
2329
|
+
onChange: function () { commitStartMode(on); },
|
|
2330
|
+
}),
|
|
2331
|
+
h("span", { className: "omd-toolName" }, label));
|
|
2332
|
+
}
|
|
2333
|
+
return h("div", { className: "omd-mainName" },
|
|
2334
|
+
h("div", { className: "omd-glabel" }, "启动方式"),
|
|
2335
|
+
h("div", { className: "omd-nameRow" },
|
|
2336
|
+
smOption("fresh", "全新(fresh)", !fork, false),
|
|
2337
|
+
smOption("fork", "继承对话(fork)", fork, true)),
|
|
2338
|
+
fork
|
|
2339
|
+
? h("div", { className: "omd-hint" },
|
|
2340
|
+
"继承对话的子代理以主 agent 已完成的对话轮次为初始内容启动(一次性快照,之后两边各自推进);工具面仍以本角色配置为准。")
|
|
2341
|
+
: null,
|
|
2342
|
+
fork && hasModel
|
|
2343
|
+
? statusRow("omd-statusWarn", ic(P.IconWarningOutline16, 16), ROLE_SM_FORK_MODEL_HINT)
|
|
2344
|
+
: null);
|
|
2345
|
+
}
|
|
2346
|
+
|
|
2234
2347
|
function roleCard(name) {
|
|
2235
2348
|
var isMain = name === "__main__";
|
|
2236
2349
|
var display = isMain ? "主 agent" : name;
|
|
@@ -2336,9 +2449,12 @@ window.__ModuleLoader__.load({
|
|
|
2336
2449
|
// warn 并忽略)。留空 = 跟随主 agent 当前模型。
|
|
2337
2450
|
// 「会话模式」单选紧随模型行(内置 / 自定义通用):缺省一次性,
|
|
2338
2451
|
// 选可续时行内给成本提示 + persistence 缺失警告(如有)。
|
|
2452
|
+
// 「启动方式」单选紧随会话模式行(内置 / 自定义通用):缺省全新,
|
|
2453
|
+
// 选继承对话时行内给快照语义提示;配了专用模型再叠加互斥警告。
|
|
2339
2454
|
body.push(roleTitleBlock(name, isCustom));
|
|
2340
2455
|
body.push(roleModelBlock(name));
|
|
2341
2456
|
body.push(roleBgModeBlock(name));
|
|
2457
|
+
body.push(roleStartModeBlock(name));
|
|
2342
2458
|
// 三组网格(同 roleCandidateTools 注释的分组口径):「基础工具」=
|
|
2343
2459
|
// 非 mcp__ 且不在检测库存(blocks ∪ customCoreToolsOf 减 inventory);
|
|
2344
2460
|
// 「MCP 工具」= mcp__ 前缀(含 SRC 自带行,如 tavily);「插件工具」
|
|
@@ -2457,6 +2573,15 @@ window.__ModuleLoader__.load({
|
|
|
2457
2573
|
// 配置对象(全局默认 / 各工作区,标签页)
|
|
2458
2574
|
workspaceBarOf(),
|
|
2459
2575
|
|
|
2576
|
+
// 宿主工作区列表拉取失败的可见降级提示:此时标签条只剩配置文件兜底的
|
|
2577
|
+
// tab,一声不吭的话用户会误以为「注册过的工作区不见了」是功能缺陷。
|
|
2578
|
+
// 仅请求失败 / 响应异常时出现(wsListErr 非空,成功路径零占位);贴在
|
|
2579
|
+
// 标签条容器下方另起一行,不动标签行自身的收纳 / 下拉锚点布局,
|
|
2580
|
+
// role=status 礼貌播报即可(持久化警告同款 statusRow,错误行才用 alert)。
|
|
2581
|
+
wsListErr
|
|
2582
|
+
? statusRow("omd-statusWarn", ic(P.IconWarningOutline16, 16), wsListErr, "status")
|
|
2583
|
+
: null,
|
|
2584
|
+
|
|
2460
2585
|
// 「添加工作区」弹窗:fixed 全屏遮罩不占布局流,挂在根数组末尾即可;
|
|
2461
2586
|
// 未打开时返回 null,零开销
|
|
2462
2587
|
wsModalOf(),
|
|
@@ -2977,8 +3102,9 @@ window.__ModuleLoader__.load({
|
|
|
2977
3102
|
// Esc(只收菜单 / 建议下拉 / 弹窗,不关页);确认弹窗开着时由 ConfirmLayer
|
|
2978
3103
|
// 的捕获级监听截停(只关确认框);事件都到不了这里。其余位置 Esc 一律关页。
|
|
2979
3104
|
// 一键升级(页头更新卡「升级」按钮,统一入口):
|
|
2980
|
-
// POST /api/paoding/upgrade
|
|
2981
|
-
//
|
|
3105
|
+
// POST /api/paoding/upgrade,服务端经插件通道原地换版本(常规 profile 走
|
|
3106
|
+
// dsh 插件转发器;desktop profile 被 dsh CLI 的 Electron 专属守卫硬拒,
|
|
3107
|
+
// 服务端直跑 pnpm add),分钟级操作。确认弹窗(原原生 confirm
|
|
2982
3108
|
// 改通用确认弹窗,confirmCtrl 单例见 70 片段)文案按挂载形态分流:
|
|
2983
3109
|
// dev link 直连形态(layout 由服务端 version 路由按包根 .git 判定)无法
|
|
2984
3110
|
// 就地升级,把手动切换命令说在前头;installed(registry 版)原地换版本,
|
|
@@ -2990,7 +3116,7 @@ window.__ModuleLoader__.load({
|
|
|
2990
3116
|
var isDev = verInfo.layout === "dev";
|
|
2991
3117
|
var msg = isDev
|
|
2992
3118
|
? "当前为开发 link 直连形态:无法就地升级,请手动执行 dsh plugin add dsh-paoding@latest 切换到 registry 版本。仍要继续尝试吗?"
|
|
2993
|
-
: "确定升级到 " + versionTagOf(verInfo.latest) + "
|
|
3119
|
+
: "确定升级到 " + versionTagOf(verInfo.latest) + "?升级将通过插件通道原地换版本,完成后需重启 DSH 生效。";
|
|
2994
3120
|
confirmCtrl.ask({
|
|
2995
3121
|
title: "升级 dsh-paoding",
|
|
2996
3122
|
body: msg,
|
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
and fix in place — resuming keeps the child's accumulated context, while
|
|
49
49
|
re-delegating starts a cold task and repeats finished work. Only re-delegate
|
|
50
50
|
when the child session is gone or the task needs a different role.
|
|
51
|
+
- A send_message that returned a delivery confirmation has been stored by the child
|
|
52
|
+
session — never resend it while awaiting the reply; collect the result via the
|
|
53
|
+
completion notification or job_output instead. Resend only when the send itself
|
|
54
|
+
failed (nothing was stored) or the child session is confirmed gone.
|
|
51
55
|
- If the same task fails twice, stop retrying: report to the user what failed, why,
|
|
52
56
|
and what you already tried. Never loop a failing delegation.
|
|
53
57
|
- When re-delegating (fresh task or continuation), always include your integration
|
|
@@ -209,7 +213,9 @@
|
|
|
209
213
|
|
|
210
214
|
# ── 角色委派工具 ─────────────────────────────────────────────
|
|
211
215
|
# 每个实例把一个 spawn provider 绑定到一个 toolName;主 agent 调哪个工具,
|
|
212
|
-
# 即选择该子 agent
|
|
216
|
+
# 即选择该子 agent 的工具面。块级 provider 也可写 fork —— 子 agent 以主 agent
|
|
217
|
+
# 已完成的对话轮次为初始内容启动(庖丁经 roles.<toolName>.start_mode 配置),
|
|
218
|
+
# 其余生成期行为不变。子 agent 创建时 tools.restrict(toolFilter)
|
|
213
219
|
# 校验 allow 名字必须存在于其可见注册面 —— 本组合(standard 全量 + host
|
|
214
220
|
# patch 的 mcp/memory)就是这些名字的来源,缺一行都会报 unknown tools。
|
|
215
221
|
|
package/tools/lib/alloc.mjs
CHANGED
|
@@ -17,9 +17,12 @@ import { ROLES } from './util.mjs'
|
|
|
17
17
|
* and as the suggested values shown in the visual config UI. codegraph and
|
|
18
18
|
* memory_search stay on
|
|
19
19
|
* the main agent (matching the static preset); other MCP tools are suggested
|
|
20
|
-
* by tool-name keywords. 角色条目形状 { model, provider, background_mode, persona, tools }:
|
|
20
|
+
* by tool-name keywords. 角色条目形状 { model, provider, start_mode, background_mode, persona, tools }:
|
|
21
21
|
* model / provider(角色专用模型)在此恒为 null(= 不注入 agentOptions,子 agent
|
|
22
|
-
* 继承主 agent 当前模型),仅配置文件 / 配置面板 4d 显式设置;
|
|
22
|
+
* 继承主 agent 当前模型),仅配置文件 / 配置面板 4d 显式设置;start_mode
|
|
23
|
+
* (roles.<toolName>.start_mode,角色启动方式)在此恒为 'fresh'(= 块级 provider
|
|
24
|
+
* 行保持 spawn,子 agent 全新启动),仅配置文件 / 配置面板显式设置为 'fork';
|
|
25
|
+
* background_mode
|
|
23
26
|
* (roles.<toolName>.background_mode,可续模式)在此恒为 'one-shot'(= 不注入
|
|
24
27
|
* backgroundMode 行,dsh-tool-subagent 缺省即 one-shot),仅配置文件 / 配置面板
|
|
25
28
|
* 显式设置为 'continuable'。
|
|
@@ -35,7 +38,7 @@ export function smartDefaults(mcpReports, inventory, staticBase) {
|
|
|
35
38
|
const assign = (role) => {
|
|
36
39
|
// 与 baseAssignments / resolveAssignments 同形状(name 恒 null = 不改名):
|
|
37
40
|
// 缺 name 键会让下游形状断言/序列化层按缺省处理,和 baseAssignments 不一致。
|
|
38
|
-
roles[role] ??= { name: null, model: null, provider: null, background_mode: 'one-shot', persona: null, tools: [...staticBase[role]] }
|
|
41
|
+
roles[role] ??= { name: null, model: null, provider: null, start_mode: 'fresh', background_mode: 'one-shot', persona: null, tools: [...staticBase[role]] }
|
|
39
42
|
for (const t of tools) if (!roles[role].tools.includes(t)) roles[role].tools.push(t)
|
|
40
43
|
}
|
|
41
44
|
if (server === 'codegraph') {
|
|
@@ -77,8 +80,9 @@ export function keywords(names, pattern) {
|
|
|
77
80
|
* 或 --auto)先装完可用基础版,host 工具留给用户在侧栏底部「庖丁配置」入口
|
|
78
81
|
* 里显式开启,避免智能默认把检测到的 host 工具静默塞进委派链。形状与 smartDefaults
|
|
79
82
|
* 返回值完全一致,生成层 / 序列化层无需区分来源;staticBase 复制而非别名,
|
|
80
|
-
* 防调用方原地改写。每个内置角色条目显式带
|
|
81
|
-
* serializeConfig 恒写出 —— fresh
|
|
83
|
+
* 防调用方原地改写。每个内置角色条目显式带 start_mode: 'fresh' 与
|
|
84
|
+
* background_mode: 'one-shot',随 serializeConfig 恒写出 —— fresh 落盘的配置
|
|
85
|
+
* 文件里旋钮可见。
|
|
82
86
|
*/
|
|
83
87
|
export function baseAssignments(staticBase) {
|
|
84
88
|
const roles = {}
|
|
@@ -87,7 +91,7 @@ export function baseAssignments(staticBase) {
|
|
|
87
91
|
// 一律剔除 mcp__ 前缀名(KNOWN_HOST_PLUGINS 工具不在 staticBase 里,无需再滤),
|
|
88
92
|
// 保证落盘的配置文件只含 dsh 基础工具 —— host 工具全部经 UI 显式开启。
|
|
89
93
|
const baseTools = (staticBase[role] ?? []).filter((name) => !name.startsWith('mcp__'))
|
|
90
|
-
roles[role] = { name: null, model: null, provider: null, background_mode: 'one-shot', persona: null, tools: [...baseTools] }
|
|
94
|
+
roles[role] = { name: null, model: null, provider: null, start_mode: 'fresh', background_mode: 'one-shot', persona: null, tools: [...baseTools] }
|
|
91
95
|
}
|
|
92
96
|
return {
|
|
93
97
|
roles,
|
|
@@ -108,8 +112,9 @@ export function baseAssignments(staticBase) {
|
|
|
108
112
|
* main_agent_remove, main_agent_skills, main_agent_skills_inline,
|
|
109
113
|
* main_agent_persona_extra, main_agent_display_name, skills };
|
|
110
114
|
* roles 条目形状
|
|
111
|
-
* { name, model, provider, background_mode, persona, tools }(model / provider =
|
|
112
|
-
* 角色专用模型,缺省 null = 不注入 agentOptions;
|
|
115
|
+
* { name, model, provider, start_mode, background_mode, persona, tools }(model / provider =
|
|
116
|
+
* 角色专用模型,缺省 null = 不注入 agentOptions;start_mode = 角色启动方式,
|
|
117
|
+
* 缺省 'fresh' = 块级 provider 行保持 spawn;background_mode = 角色可续模式,
|
|
113
118
|
* 缺省 'one-shot' = 不注入 backgroundMode 行)。
|
|
114
119
|
*/
|
|
115
120
|
export function resolveAssignments(existing, suggested, staticBase) {
|
|
@@ -124,6 +129,9 @@ export function resolveAssignments(existing, suggested, staticBase) {
|
|
|
124
129
|
name: role.name ?? null,
|
|
125
130
|
model: role.model ?? null,
|
|
126
131
|
provider: role.provider ?? null,
|
|
132
|
+
// 缺键(老配置 / UI 手工构造的半成品对象)回落 'fresh';非法值由
|
|
133
|
+
// 生成层按「非 'fork' 即 fresh」口径兜底。
|
|
134
|
+
start_mode: role.start_mode ?? 'fresh',
|
|
127
135
|
// 缺键(老配置 / UI 手工构造的半成品对象)回落 'one-shot';非法值由
|
|
128
136
|
// 生成层按「非 'continuable' 即 one-shot」口径兜底。
|
|
129
137
|
background_mode: role.background_mode ?? 'one-shot',
|
package/tools/lib/compose.mjs
CHANGED
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
* (renderCustomRoleBlocks / firstLine / insertCustomRoles)、roles_remove 委派行
|
|
7
7
|
* span 删除(delegationRowSpan / composeMainPersonaEdit)、角色专用模型注入
|
|
8
8
|
* (injectRoleAgentOptions,roles.<toolName>.model / .provider → 内置角色委派块
|
|
9
|
-
* 的 agentOptions
|
|
9
|
+
* 的 agentOptions 子块)、角色启动方式改写(injectRoleStartMode,
|
|
10
|
+
* roles.<toolName>.start_mode = 'fork' → 内置角色委派块的块级 provider 行原位
|
|
11
|
+
* 改写为 fork;'fresh' 不动源行 —— 源模板四块各预置 `provider: spawn`,全默认
|
|
12
|
+
* 产物与源零 diff;块内无该行时不兜底注入,与 backgroundMode 的兜底口径不同,
|
|
13
|
+
* 见函数注释)、角色可续模式改写/兜底注入(injectRoleBackgroundMode,
|
|
10
14
|
* roles.<toolName>.background_mode = 'continuable' → 内置角色委派块的
|
|
11
15
|
* backgroundMode 行:源模板已预置该行时原位改写其值,块内无该行时在 toolName
|
|
12
16
|
* 行行尾兜底注入;'one-shot' 不动源行 —— 源模板四块各预置
|
|
@@ -116,6 +120,35 @@ function normalizeRoleModel(toolName, rawModel, rawProvider) {
|
|
|
116
120
|
return { model, provider }
|
|
117
121
|
}
|
|
118
122
|
|
|
123
|
+
/** 角色启动方式兜底(自定义块渲染与内置角色注入两处共用):assignments 可能绕过
|
|
124
|
+
* config 规范化(UI 手工构造 / 测试直传),compose 层按「恰好 'fork' 才认」口径
|
|
125
|
+
* 兜底 —— 与 background_mode 的「非 'continuable' 即 one-shot」同款;其余一律
|
|
126
|
+
* 'fresh'(零 diff 不动源行)。 */
|
|
127
|
+
function roleStartModeOf(role) {
|
|
128
|
+
return role?.start_mode === 'fork' ? 'fork' : 'fresh'
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 角色专用模型解析(fork 互斥判定版,normalizeRoleModel 的调用方统一走这里):
|
|
133
|
+
* 先归一 model / provider(含 provider-alone warn),再判 fork 互斥 ——
|
|
134
|
+
* start_mode: 'fork' 的子 agent 以主 agent(父级)的提供方与模型启动(DSH fork
|
|
135
|
+
* 后端为 KV cache 复用的硬约束),专用模型不生效:warn 说明后按缺省处理(不注入
|
|
136
|
+
* agentOptions),与 provider-alone 的「warn 后忽略」同款。fork + provider-alone
|
|
137
|
+
* 不叠加 fork warn(provider-alone 已在 normalizeRoleModel 里 warn 过)。'fresh'
|
|
138
|
+
* 行为与 normalizeRoleModel 完全一致。
|
|
139
|
+
*/
|
|
140
|
+
function resolveRoleModel(toolName, rawModel, rawProvider, startMode) {
|
|
141
|
+
const { model, provider } = normalizeRoleModel(toolName, rawModel, rawProvider)
|
|
142
|
+
if (startMode === 'fork' && model !== null) {
|
|
143
|
+
warn(
|
|
144
|
+
`roles.${toolName}: start_mode: 'fork' 的子 agent 继承主 agent 的模型,` +
|
|
145
|
+
`专用模型 '${model}' 不生效,已忽略(agentOptions 不注入)`,
|
|
146
|
+
)
|
|
147
|
+
return { model: null, provider: null }
|
|
148
|
+
}
|
|
149
|
+
return { model, provider }
|
|
150
|
+
}
|
|
151
|
+
|
|
119
152
|
/**
|
|
120
153
|
* 自定义角色 toolName 保留名校验:与内置角色(ROLES)、restrict.mjs 主 agent
|
|
121
154
|
* allow 白名单(restrictBase)、顶层 subagent / subagent_fork 撞名的 toolName
|
|
@@ -203,14 +236,19 @@ export function renderCustomRoleBlocks(roles, skillsMap, restrictBase = []) {
|
|
|
203
236
|
toolName,
|
|
204
237
|
skillsMap,
|
|
205
238
|
)
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
// provider
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
|
|
239
|
+
// 角色专用模型、启动方式与可续模式(roles.<toolName>.model / .provider /
|
|
240
|
+
// .start_mode / .background_mode):自定义角色与内置角色同形状(provider /
|
|
241
|
+
// toolName / agentOptions? / backgroundMode / persona / toolFilter)。启动方式
|
|
242
|
+
// 恰好 'fork' 才认(其余一律 fresh,见 roleStartModeOf):fork 时块级
|
|
243
|
+
// provider 行落 fork(子 agent 以主 agent 已完成的对话轮次为初始内容启动),
|
|
244
|
+
// 否则恒 spawn。先归一再判 provider-alone(防 UI / 手工构造的 assignments 绕过
|
|
245
|
+
// 规范化);fork 与专用模型互斥(fork 子 agent 继承主 agent 的提供方与模型),
|
|
246
|
+
// 经 resolveRoleModel 判定 —— 命中 warn 后按缺省处理,仅 model 非 null 才插
|
|
247
|
+
// agentOptions 子块,provider-alone 仅 warn 忽略。backgroundMode 行恒写(与
|
|
248
|
+
// 内置块源模板预置口径一致:行始终可见),continuable → continuable,
|
|
249
|
+
// one-shot/缺省/异常值 → one-shot(与 config 解析回落口径一致)。
|
|
250
|
+
const startMode = roleStartModeOf(role)
|
|
251
|
+
const { model, provider } = resolveRoleModel(toolName, role.model ?? null, role.provider ?? null, startMode)
|
|
214
252
|
// agentOptions 子行(键序固定 provider 在前、model 在后,与 dsh-tool-subagent
|
|
215
253
|
// Config 字段序一致);model 缺省时整块不出现。
|
|
216
254
|
const agentOptionsLines = []
|
|
@@ -228,7 +266,9 @@ export function renderCustomRoleBlocks(roles, skillsMap, restrictBase = []) {
|
|
|
228
266
|
` - id: delegation-${toolName}`,
|
|
229
267
|
` name: '@deepseek-ai/dsh-tool-subagent'`,
|
|
230
268
|
' config:',
|
|
231
|
-
|
|
269
|
+
// 块级 provider = 启动方式(spawn 全新启动 / fork 继承主 agent 已完成
|
|
270
|
+
// 轮次),与 10 空格缩进的 agentOptions.provider(LLM 路由)分属两处。
|
|
271
|
+
` provider: ${startMode === 'fork' ? 'fork' : 'spawn'}`,
|
|
232
272
|
// toolName / 工具条目过 yamlScalar:纯数字、YAML 字面量形态等歧义名
|
|
233
273
|
// 必须带引号落盘,否则委派行会被解析成数字/布尔/null。
|
|
234
274
|
` toolName: ${yamlScalar(toolName)}`,
|
|
@@ -397,11 +437,12 @@ export function delegationRowSpan(srcText, role) {
|
|
|
397
437
|
}
|
|
398
438
|
|
|
399
439
|
/**
|
|
400
|
-
* 内置角色委派块边界定位(roleToolNameLineEnd /
|
|
440
|
+
* 内置角色委派块边界定位(roleToolNameLineEnd / injectRoleStartMode /
|
|
441
|
+
* injectRoleBackgroundMode 共用):
|
|
401
442
|
* 块定位 `- id: delegation-<rowId>`(rowId = 角色名 `_` 换 `-`,找不到 throw);
|
|
402
443
|
* 块结束 = min(其后首个 `\n - id: delegation-` 下标, '# ── remaining
|
|
403
444
|
* model-facing rows' 注释下标, srcText.length),保证块内行搜索不越界命中
|
|
404
|
-
* 别的块。errorKey 用于把报错归因到具体配置键(model / background_mode)。
|
|
445
|
+
* 别的块。errorKey 用于把报错归因到具体配置键(model / start_mode / background_mode)。
|
|
405
446
|
*/
|
|
406
447
|
function roleDelegationBlockBounds(srcText, role, errorKey) {
|
|
407
448
|
const rowId = role.replace(/_/g, '-') // 委派行 id 用连字符(toolName 用下划线)
|
|
@@ -503,6 +544,37 @@ export function injectRoleBackgroundMode(srcText, role) {
|
|
|
503
544
|
return { start: lineEnd, end: lineEnd, text: '\n backgroundMode: continuable' }
|
|
504
545
|
}
|
|
505
546
|
|
|
547
|
+
/**
|
|
548
|
+
* 角色启动方式改写(roles.<toolName>.start_mode = 'fork' 生效路径):把该内置
|
|
549
|
+
* 角色委派块内 8 空格缩进的块级 `provider: spawn` 行原位改写为
|
|
550
|
+
* `provider: fork`,子 agent 以主 agent(父级)已完成的对话轮次为初始内容启动。
|
|
551
|
+
* 锚点定位复用 roleDelegationBlockBounds,行搜索限定块内(不越界命中别的块);
|
|
552
|
+
* 行首带 \n 且恰 8 空格,10 空格缩进的 agentOptions.provider 子行(LLM 路由)
|
|
553
|
+
* 形态不匹配,天然区分 —— 块级 provider(启动提供方)与 agentOptions 子行
|
|
554
|
+
* (模型路由)分属两处,互不相干。
|
|
555
|
+
* 返回 span edit { start, end, text }(整行原位改写,坐标为源文本原坐标,与
|
|
556
|
+
* allow/persona/删除 edits 一起按 start 降序应用)。无任何改动时返回 null:
|
|
557
|
+
* - 'fresh'(含缺省):不动源行 —— 源模板四块各预置 `provider: spawn`,全默认
|
|
558
|
+
* 配置的生成产物与源逐字节一致(零 diff 不变量);
|
|
559
|
+
* - 行已是 fork:幂等返回 null;
|
|
560
|
+
* - 块内无 provider 行:不兜底注入,静默保留原样 —— 与 injectRoleBackgroundMode
|
|
561
|
+
* 的「缺行兜底注入」口径刻意不同:backgroundMode 是产品旋钮(源模板为可见性
|
|
562
|
+
* 预置),而块级 provider 行是委派块的骨架配置,缺失即模板损坏;半截注入
|
|
563
|
+
* 救不了坏模板,静默保留比产出难排查的配置更稳妥,模板漂移由恒等性金测兜底。
|
|
564
|
+
* 调用方(composeGenerated)仅对 'fork' 调本函数。
|
|
565
|
+
*/
|
|
566
|
+
export function injectRoleStartMode(srcText, role) {
|
|
567
|
+
const { idx, blockEnd } = roleDelegationBlockBounds(srcText, role, 'start_mode')
|
|
568
|
+
// 块内 span 查块级 provider 行:8 空格缩进(config 键层),行首带 \n 保证不误
|
|
569
|
+
// 匹配块首部分行或 persona 内容行;锚点含 'spawn' 值,10 空格的
|
|
570
|
+
// agentOptions.provider(其缩进多两格,前缀不命中)天然被排除。
|
|
571
|
+
const providerMarker = '\n provider: spawn'
|
|
572
|
+
const providerIdx = srcText.indexOf(providerMarker, idx)
|
|
573
|
+
if (providerIdx === -1 || providerIdx >= blockEnd) return null
|
|
574
|
+
const lineStart = providerIdx + 1 // 跳过行首 \n,定位到行首
|
|
575
|
+
return { start: lineStart, end: lineStart + providerMarker.length - 1, text: ' provider: fork' }
|
|
576
|
+
}
|
|
577
|
+
|
|
506
578
|
/**
|
|
507
579
|
* 主 persona 整块改造(删委派 bullet + 自定义角色自动委派行),返回一个
|
|
508
580
|
* span edit { start, end, text }(start/end 为源文本原坐标、随其它 edits 降序应用),
|
|
@@ -709,22 +781,31 @@ export function composeGenerated(srcText, blocks, personaBlocks, assignments, in
|
|
|
709
781
|
const personaEdit = composeMainPersonaEdit(srcText, removedRoles, customBullets)
|
|
710
782
|
if (personaEdit !== null) edits.push(personaEdit)
|
|
711
783
|
|
|
712
|
-
// 角色专用模型 / 可续模式注入(roles.<toolName>.model / .provider →
|
|
713
|
-
// agentOptions;roles.<toolName>.
|
|
714
|
-
//
|
|
715
|
-
//
|
|
716
|
-
//
|
|
717
|
-
//
|
|
784
|
+
// 角色专用模型 / 启动方式 / 可续模式注入(roles.<toolName>.model / .provider →
|
|
785
|
+
// 委派块 agentOptions;roles.<toolName>.start_mode = 'fork' → 委派块块级
|
|
786
|
+
// provider 行原位改写 fork;roles.<toolName>.background_mode = 'continuable' →
|
|
787
|
+
// 委派块 backgroundMode 行改写/兜底注入):与 roles_remove 委派行删除 edits 同段
|
|
788
|
+
// 收集。被删角色不注入(委派行已整条删除,模型 / start_mode / background_mode
|
|
789
|
+
// 配置 warn 忽略);fork 与专用模型互斥(fork 子 agent 继承主 agent 的提供方与
|
|
790
|
+
// 模型,KV cache 复用硬约束),经 resolveRoleModel 判定 —— 命中 warn 后按缺省
|
|
791
|
+
// 处理(不注入 agentOptions),provider-alone 仅 warn 忽略(先 normalize 再判断,
|
|
792
|
+
// 防手工构造的 assignments 绕过规范化);start_mode 仅 'fork' 才调
|
|
793
|
+
// injectRoleStartMode('fresh'/缺省不调 —— 源模板四块各预置的 `provider: spawn`
|
|
794
|
+
// 原样保留,全默认配置生成产物与源逐字节一致),background_mode 仅 'continuable'
|
|
718
795
|
// 才调 injectRoleBackgroundMode('one-shot'/缺省不调 —— 源模板四块各预置的
|
|
719
796
|
// `backgroundMode: one-shot` 原样保留,全默认配置生成产物与源逐字节一致)。
|
|
720
797
|
// 键序与收集序:源块已有该行时走改写路径(edit start = 既有行行首,位于
|
|
721
798
|
// toolName 行行尾之后 → 降序应用先改写该行,agentOptions 随后插在更前的
|
|
722
799
|
// toolName 行行尾,键序 toolName → agentOptions? → backgroundMode 自然成立);
|
|
723
|
-
//
|
|
800
|
+
// startMode 改写的 provider 行在 toolName 行之前(块内键序 provider → toolName),
|
|
801
|
+
// edit start 更小 → 降序应用最后生效,与上述键序互不干扰;源块无该行时走兜底
|
|
802
|
+
// 注入路径,与 agentOptions 同锚点(start 相等)→ backgroundMode
|
|
724
803
|
// edit 必须先于 agentOptions edit 收集(先收集者居后),与自定义块键序一致。
|
|
725
804
|
for (const role of ROLES) {
|
|
726
805
|
const rawModel = assignments.roles[role]?.model ?? null
|
|
727
806
|
const rawProvider = assignments.roles[role]?.provider ?? null
|
|
807
|
+
// compose 层兜底:恰好 'fork' 才认,其余(缺省/异常值)一律 fresh(见 roleStartModeOf)。
|
|
808
|
+
const startMode = roleStartModeOf(assignments.roles[role])
|
|
728
809
|
const rawBackgroundMode = assignments.roles[role]?.background_mode ?? null
|
|
729
810
|
if (removedRoles.includes(role)) {
|
|
730
811
|
const model = normalizeModelRef(rawModel, `roles.${role}.model`)
|
|
@@ -732,6 +813,9 @@ export function composeGenerated(srcText, blocks, personaBlocks, assignments, in
|
|
|
732
813
|
if (model !== null || provider !== null) {
|
|
733
814
|
warn(`roles.${role}.model: 该角色已在 roles_remove 中删除,模型配置被忽略`)
|
|
734
815
|
}
|
|
816
|
+
if (startMode === 'fork') {
|
|
817
|
+
warn(`roles.${role}.start_mode: 该角色已在 roles_remove 中删除,start_mode 配置被忽略`)
|
|
818
|
+
}
|
|
735
819
|
if (rawBackgroundMode === 'continuable') {
|
|
736
820
|
warn(`roles.${role}.background_mode: 该角色已在 roles_remove 中删除,background_mode 配置被忽略`)
|
|
737
821
|
}
|
|
@@ -741,8 +825,12 @@ export function composeGenerated(srcText, blocks, personaBlocks, assignments, in
|
|
|
741
825
|
const backgroundModeEdit = injectRoleBackgroundMode(srcText, role)
|
|
742
826
|
if (backgroundModeEdit !== null) edits.push(backgroundModeEdit)
|
|
743
827
|
}
|
|
744
|
-
const { model, provider } =
|
|
828
|
+
const { model, provider } = resolveRoleModel(role, rawModel, rawProvider, startMode)
|
|
745
829
|
if (model !== null) edits.push(injectRoleAgentOptions(srcText, role, model, provider))
|
|
830
|
+
if (startMode === 'fork') {
|
|
831
|
+
const startModeEdit = injectRoleStartMode(srcText, role)
|
|
832
|
+
if (startModeEdit !== null) edits.push(startModeEdit)
|
|
833
|
+
}
|
|
746
834
|
}
|
|
747
835
|
// 注入 edit(零宽,位于 toolName 行行尾)与该块的 allow edit / persona edit
|
|
748
836
|
// 区间天然不相交:委派块内 toolName 行先于 persona / toolFilter 出现,插入点
|