@morlay/dsh-session-mode 0.0.1-alpha.4 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -67
- package/dist/client.cjs +165 -802
- package/dist/client.d.cts +22 -187
- package/dist/client.d.mts +22 -187
- package/dist/index.d.cts +183 -9
- package/dist/index.d.mts +183 -9
- package/dist/index.mjs +183 -31
- package/dist/rows.d.cts +38 -0
- package/dist/rows.d.mts +38 -0
- package/dist/rows.mjs +503 -0
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +46 -53
- package/src/client/SessionModeSeat.tsx +38 -19
- package/src/client/index.ts +143 -92
- package/src/client/locales.ts +18 -72
- package/src/index.ts +145 -18
- package/{tool/modes.ts → src/mode-sources.ts} +32 -14
- package/src/modes.ts +197 -36
- package/src/rows.ts +57 -0
- package/cordis.patch.yml +0 -69
- package/dist/shared-FNWe-_rS.d.cts +0 -106
- package/dist/shared-FNWe-_rS.d.mts +0 -106
- package/src/client/ModelDefaultsCard.styles.ts +0 -134
- package/src/client/ModelDefaultsCard.tsx +0 -233
- package/src/client/SessionModeLabel.module.css +0 -24
- package/src/client/SessionModeLabel.tsx +0 -44
- package/src/client/model-defaults-card-controller.ts +0 -408
- package/tool/patch.ts +0 -91
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,11 @@ import { z } from "zod";
|
|
|
5
5
|
import z$1 from "@deepseek-ai/schemastery";
|
|
6
6
|
import { PERSONA_PREFIX_SECTION, PERSONA_SUFFIX_SECTION } from "@deepseek-ai/dsh-system-prompt";
|
|
7
7
|
//#region src/modes.ts
|
|
8
|
+
/**
|
|
9
|
+
* 本地化说明:`description()` 的类型签名只声明 `string`,而 meta 本身接受 `Dict<string>`
|
|
10
|
+
* (`vendor/schemastery/src/index.ts` 的 `mergeDesc` 就是按字典合并的),所以这里只做一次类型放行。
|
|
11
|
+
*/
|
|
12
|
+
const localized = (text) => text;
|
|
8
13
|
const personaSchema = z$1.object({
|
|
9
14
|
prefix: z$1.string().default(""),
|
|
10
15
|
suffix: z$1.string().default("")
|
|
@@ -13,23 +18,72 @@ const personaSchema = z$1.object({
|
|
|
13
18
|
const roleSchema = z$1.union([z$1.const("main"), z$1.const("subagent")]);
|
|
14
19
|
/** 默认模型的形状与全局 `agent-default-model` 一致;省略 effort 就跟 provider 默认。 */
|
|
15
20
|
const modelSchema = z$1.object({
|
|
16
|
-
provider: z$1.string().
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
provider: z$1.string().role("select", { source: "llm-providers" }).description(localized({
|
|
22
|
+
zh: "服务商 id(部署里注册的任意路由,不论哪个适配器插件注册的)。",
|
|
23
|
+
en: "Provider id (any route registered in this deployment, whichever adapter plugin supplies it)."
|
|
24
|
+
})),
|
|
25
|
+
model: z$1.string().role("select", { source: "llm-models" }).description(localized({
|
|
26
|
+
zh: "模型 id。",
|
|
27
|
+
en: "Model id."
|
|
28
|
+
})),
|
|
29
|
+
reasoningEffort: z$1.string().description(localized({
|
|
30
|
+
zh: "思考档位;省略就跟服务商自己的默认。",
|
|
31
|
+
en: "Reasoning effort; unset keeps the provider's own default."
|
|
32
|
+
}))
|
|
19
33
|
});
|
|
20
34
|
const modeSchema = z$1.object({
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
preset: z$1.string().default("").description(localized({
|
|
36
|
+
zh: "这个模式挂哪个 agent preset(它的 id,官方或本部署自建的):行清单由那个 preset 提供,几个模式可以共享同一个;空串表示不挂(只能由 applyTo / 继承使用)。",
|
|
37
|
+
en: "Which agent preset this mode rides on (its id, shipped or deployment-owned): that preset supplies the row list and several modes may share it; empty means none (usable only through applyTo / inheritance)."
|
|
38
|
+
})),
|
|
39
|
+
name: z$1.string().required().description(localized({
|
|
40
|
+
zh: "模式名(事实文案;选择面归官方 roster)。",
|
|
41
|
+
en: "Mode name (fact copy; the picker belongs to the official roster)."
|
|
42
|
+
})),
|
|
43
|
+
description: z$1.string().default("").description(localized({
|
|
44
|
+
zh: "一句话说明。",
|
|
45
|
+
en: "One-line description."
|
|
46
|
+
})),
|
|
47
|
+
role: z$1.array(roleSchema).default(["main"]).description(localized({
|
|
48
|
+
zh: "谁可以用这个模式:`main`(会话选择器里可选)或 `subagent`(子代理继承)。",
|
|
49
|
+
en: "Who may use this mode: `main` (selectable in sessions) or `subagent` (inherited by subagents)."
|
|
50
|
+
})),
|
|
24
51
|
persona: personaSchema.default({}),
|
|
25
|
-
allowTools: z$1.array(z$1.string()).default([])
|
|
26
|
-
|
|
27
|
-
|
|
52
|
+
allowTools: z$1.array(z$1.string()).default([]).description(localized({
|
|
53
|
+
zh: "这个会话能用的工具;其余既不进目录,调用也被拒。",
|
|
54
|
+
en: "Tools this session may use; everything else leaves the catalog and calls are refused."
|
|
55
|
+
})),
|
|
56
|
+
instructions: z$1.boolean().default(true).description(localized({
|
|
57
|
+
zh: "是否要 instruction 类注入(工作区指令、技能目录、用法正文)。",
|
|
58
|
+
en: "Whether instruction-class injections apply (workspace instructions, skill catalog, guidance)."
|
|
59
|
+
})),
|
|
60
|
+
runtimeContext: z$1.boolean().default(true).description(localized({
|
|
61
|
+
zh: "是否要动态快照(文件沙箱策略、审批策略)。",
|
|
62
|
+
en: "Whether the runtime snapshot applies (sandbox and approval policy)."
|
|
63
|
+
})),
|
|
64
|
+
/**
|
|
65
|
+
* 这个模式的默认模型。不标 `volatile`:`modes` 本身就是 volatile,整棵子树都在页面上——再标一层会被
|
|
66
|
+
* schemastery 拒(`validateVolatileSchema` 不许 volatile 套 volatile)。
|
|
67
|
+
*/
|
|
68
|
+
defaultModel: modelSchema.default(null).description(localized({
|
|
69
|
+
zh: "这个模式的默认模型;省略就跟全局默认模型。只在会话还没有模型事实时接管。",
|
|
70
|
+
en: "Default model for this mode; unset follows the global default. Applies only while a session has no model fact yet."
|
|
71
|
+
}))
|
|
28
72
|
});
|
|
29
73
|
const Config = z$1.object({
|
|
30
|
-
default: z$1.string().required()
|
|
31
|
-
|
|
32
|
-
|
|
74
|
+
default: z$1.string().required().description(localized({
|
|
75
|
+
zh: "新会话(还没选过模式的会话)用哪个模式;必须是下面 `modes` 里的一个 id。",
|
|
76
|
+
en: "Mode a session starts in before anyone picks one; must be an id in `modes`."
|
|
77
|
+
})).volatile(),
|
|
78
|
+
modes: z$1.dict(modeSchema).required().description(localized({
|
|
79
|
+
zh: "模式清单:id → 定义(persona / 允许的工具 / 角色)。改它对**已运行会话**不自动生效——重挂后新建的会话、或重新应用模式的会话才用新定义。",
|
|
80
|
+
en: "Mode roster: id to definition (persona, allowed tools, role). Edits do not follow into already-running sessions; sessions created after the row is remounted use the new definition."
|
|
81
|
+
})).volatile(),
|
|
82
|
+
/**
|
|
83
|
+
* 退役字段:默认模型住在每个模式自己的 `defaultModel` 里。这里留着是为了**报错**(见 `configProblem`),
|
|
84
|
+
* 页面上不出现(`hidden()`)。
|
|
85
|
+
*/
|
|
86
|
+
models: z$1.dict(modelSchema).default({}).hidden()
|
|
33
87
|
});
|
|
34
88
|
/** 模式定义里不合法的地方(装配期 fail loud,而不是等到某个会话装配提示词时才发现)。 */
|
|
35
89
|
function configProblem(config) {
|
|
@@ -43,10 +97,13 @@ function configProblem(config) {
|
|
|
43
97
|
if (!roles(config.default).includes("main")) return `session-mode: \`default\` names ${JSON.stringify(config.default)}, which does not declare role "main"; a session that can never be re-selected is a contradiction`;
|
|
44
98
|
const empty = ids.filter((id) => (config.modes[id]?.allowTools ?? []).length === 0);
|
|
45
99
|
if (empty.length > 0) return `session-mode: mode(s) ${empty.join(", ")} declare no \`allowTools\`; list the tools instead of leaving it empty`;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
100
|
+
if (Object.keys(config.models ?? {}).length > 0) return "session-mode: `models` has moved into each mode's `defaultModel`; move the entries there and drop the top-level `models`";
|
|
101
|
+
const partial = Object.entries(config.modes).filter(([, mode]) => {
|
|
102
|
+
const model = mode.defaultModel;
|
|
103
|
+
if (model === void 0) return false;
|
|
104
|
+
return model.provider === void 0 || model.model === void 0 || model.provider.length === 0 || model.model.length === 0;
|
|
105
|
+
}).map(([id]) => id);
|
|
106
|
+
if (partial.length > 0) return `session-mode: mode(s) ${partial.join(", ")} declare \`defaultModel\` without both \`provider\` and \`model\``;
|
|
50
107
|
}
|
|
51
108
|
//#endregion
|
|
52
109
|
//#region src/persona.ts
|
|
@@ -126,23 +183,54 @@ const sessionModeProjection = {
|
|
|
126
183
|
},
|
|
127
184
|
stateVersion: 1
|
|
128
185
|
};
|
|
186
|
+
const sessionModeEditableSchema = z.boolean();
|
|
187
|
+
/**
|
|
188
|
+
* 这个会话能不能换模式的投影:空白会话为 `true`,一旦 `turn/start` 落库就永远 `false`(换模式要的是**整段
|
|
189
|
+
* 历史**的模式一致,所以"开过 turn"之后连正在跑的那个 turn 也算)。
|
|
190
|
+
*
|
|
191
|
+
* **判据只有这一处**:服务端 {@link SessionModes.select} 的拒绝与 client chip 的只读形态都读它——以前
|
|
192
|
+
* client 只能等服务端报错,现在连入口都不给,而两边的结论来自同一份会话事实。
|
|
193
|
+
*/
|
|
194
|
+
const sessionModeEditableProjection = {
|
|
195
|
+
key: "sessionModeEditable",
|
|
196
|
+
stateSchema: sessionModeEditableSchema,
|
|
197
|
+
init: () => true,
|
|
198
|
+
apply: (state, event) => state && event.type !== "turn/start",
|
|
199
|
+
wire: {
|
|
200
|
+
viewSchema: sessionModeEditableSchema,
|
|
201
|
+
view: (state) => state
|
|
202
|
+
},
|
|
203
|
+
stateVersion: 1
|
|
204
|
+
};
|
|
129
205
|
/** 模式清单、默认模式、按会话读取与切换。 */
|
|
130
206
|
var SessionModes = class extends Service {
|
|
131
|
-
config;
|
|
132
207
|
/** 每个 agent 已经装上的那一份(persona + 默认模型兜底;模式变了就换一份)。 */
|
|
133
208
|
installs = /* @__PURE__ */ new WeakMap();
|
|
209
|
+
/** 装配时的配置快照:`default` / `modes` 读它,改这两项靠 Loader 重挂这一行(已运行会话不自动换定义)。 */
|
|
210
|
+
config;
|
|
134
211
|
constructor(ctx, config) {
|
|
135
212
|
super(ctx, "sessionModes");
|
|
136
|
-
this.config =
|
|
213
|
+
this.config = {
|
|
214
|
+
default: config.default.get(),
|
|
215
|
+
modes: structuredClone(config.modes.get())
|
|
216
|
+
};
|
|
137
217
|
const problem = configProblem({
|
|
138
|
-
...config,
|
|
139
|
-
models: config.models
|
|
218
|
+
...this.config,
|
|
219
|
+
models: config.models
|
|
140
220
|
});
|
|
141
221
|
if (problem !== void 0) throw new Error(problem);
|
|
142
222
|
ctx.sessionProjections.register(sessionModeProjection);
|
|
223
|
+
ctx.sessionProjections.register(sessionModeEditableProjection);
|
|
143
224
|
ctx.on("agent/created", ({ agent }) => {
|
|
144
225
|
this.installFor(agent);
|
|
145
226
|
});
|
|
227
|
+
ctx.on("agent-preset/selected", (sessionId, preset) => {
|
|
228
|
+
const mapped = this.modeForPreset(preset);
|
|
229
|
+
const agent = ctx.agents.get(sessionId);
|
|
230
|
+
if (mapped === void 0 || agent === void 0) return;
|
|
231
|
+
if (this.ctx.sessionProjections.stateOf(agent.session, "sessionMode") !== mapped) agent.session.append("session-mode/selected", { sessionMode: mapped });
|
|
232
|
+
this.installFor(agent, mapped);
|
|
233
|
+
});
|
|
146
234
|
}
|
|
147
235
|
/** 新会话用它:config 里的 `default`。 */
|
|
148
236
|
get defaultId() {
|
|
@@ -202,22 +290,59 @@ var SessionModes = class extends Service {
|
|
|
202
290
|
}
|
|
203
291
|
/**
|
|
204
292
|
* 把某个空白会话切到某个模式。
|
|
293
|
+
*
|
|
294
|
+
* 模式带着它的 preset(`preset` 决定行清单),所以这里**先把 agent preset 换成模式声明的那个**,再落我们的
|
|
295
|
+
* 会话事实:否则 preset realm 还是旧那一套的行,而它的注入在我们的开关之外(旧形态 `chat` 挂 `minimal`、
|
|
296
|
+
* 会话的 preset 却还是 `standard` 时,上游 `agent-instructions` 会照旧把工作区指令注进这个"不要注入"的会话)。
|
|
297
|
+
*
|
|
298
|
+
* 目标 preset 与当前挂着的**相同时不切**(本部署两个模式共享同一份 preset,所以切模式通常走不到这一步):
|
|
299
|
+
* 换 preset 是一次重挂(卸旧行、装新行),没有变化就没有理由付出这个代价。
|
|
205
300
|
* @param sessionId - 目标会话(必须还没有开过 turn)。
|
|
206
301
|
* @param mode - 目标模式 id。
|
|
207
302
|
* @returns 提交后的模式 id。
|
|
208
303
|
*/
|
|
209
304
|
async select(sessionId, mode) {
|
|
210
|
-
|
|
305
|
+
const definition = this.definition(mode);
|
|
306
|
+
if (!definition.role.includes("main")) throw new Error(`模式 ${JSON.stringify(mode)} 不是用户可选的(它的 role 里没有 main)。`);
|
|
211
307
|
const session = this.ctx.sessions.get(sessionId);
|
|
212
308
|
if (session === void 0) throw new Error(`未知的会话 ${sessionId}`);
|
|
213
|
-
|
|
214
|
-
if (boundary !== void 0 && (boundary.openTurnStartSeq !== null || boundary.lastTurn > 0)) throw new Error("这个会话已经开始,模式不能再改;要换模式请新开一个会话。");
|
|
215
|
-
session.append("session-mode/selected", { sessionMode: mode });
|
|
309
|
+
if (this.ctx.sessionProjections.stateOf(session, "sessionModeEditable") === false) throw new Error("这个会话已经开始,模式不能再改;要换模式请新开一个会话。");
|
|
216
310
|
const agent = this.ctx.agents.get(sessionId);
|
|
311
|
+
const registry = this.presetRegistry();
|
|
312
|
+
if (agent !== void 0 && registry !== void 0 && definition.preset.length > 0) {
|
|
313
|
+
if (this.presetOfAgent(registry, agent) !== definition.preset) await registry.select(agent, definition.preset);
|
|
314
|
+
}
|
|
315
|
+
if (this.ctx.sessionProjections.stateOf(session, "sessionMode") !== mode) session.append("session-mode/selected", { sessionMode: mode });
|
|
217
316
|
if (agent !== void 0) this.installFor(agent);
|
|
218
317
|
return mode;
|
|
219
318
|
}
|
|
220
319
|
/**
|
|
320
|
+
* 某个 agent 当前挂着的 preset(registry 的 `composedPreset`)。
|
|
321
|
+
*
|
|
322
|
+
* 读不到时返回 `undefined`(按"未知"处理 → 该切就切):`composedPreset` 是 registry 较新的读面,替身与老
|
|
323
|
+
* 版本可能没有它;而"没挂任何 preset"(返回值 `undefined`)与"读不到"在这里是同一个结论。
|
|
324
|
+
*/
|
|
325
|
+
presetOfAgent(registry, agent) {
|
|
326
|
+
const read = registry.composedPreset;
|
|
327
|
+
if (typeof read !== "function") return void 0;
|
|
328
|
+
try {
|
|
329
|
+
return read.call(registry, agent.ctx);
|
|
330
|
+
} catch {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* 官方 preset registry:行清单与它的选择面住在那一行。不在 `inject` 里点名(headless 部署没有它,
|
|
336
|
+
* 点名会让本行永不激活),所以按"可能拿不到"读——`ctx.get` 在当前 ctx 没声明那个服务时会抛。
|
|
337
|
+
*/
|
|
338
|
+
presetRegistry() {
|
|
339
|
+
try {
|
|
340
|
+
return this.ctx.get("agentPresets");
|
|
341
|
+
} catch {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
221
346
|
* 把某个活着的 agent 切到某个模式。与 {@link select} 的差别:它不要求空白会话——子代理创建时的继承
|
|
222
347
|
* 走这里,**未来的"指定 mode"入口(模型侧或配置侧)也走这里**(那条接缝还没做)。
|
|
223
348
|
* @param agent - 目标 agent。
|
|
@@ -237,11 +362,40 @@ var SessionModes = class extends Service {
|
|
|
237
362
|
resolveModeId(agent) {
|
|
238
363
|
const selected = this.ctx.sessionProjections.stateOf(agent.session, "sessionMode");
|
|
239
364
|
if (typeof selected === "string") return selected;
|
|
365
|
+
const mapped = this.modeForPreset(this.presetOf(agent.session));
|
|
366
|
+
if (mapped !== void 0) {
|
|
367
|
+
agent.session.append("session-mode/selected", { sessionMode: mapped });
|
|
368
|
+
return mapped;
|
|
369
|
+
}
|
|
240
370
|
const inherited = this.inheritedModeId(agent);
|
|
241
371
|
if (inherited === void 0) return this.defaultId;
|
|
242
372
|
agent.session.append("session-mode/selected", { sessionMode: inherited });
|
|
243
373
|
return inherited;
|
|
244
374
|
}
|
|
375
|
+
/** 官方 roster 选定的 preset(没选过、或 registry 没装时为 `undefined`)。 */
|
|
376
|
+
presetOf(session) {
|
|
377
|
+
try {
|
|
378
|
+
const state = this.ctx.sessionProjections.stateOf(session, "agentPreset");
|
|
379
|
+
return typeof state === "string" ? state : void 0;
|
|
380
|
+
} catch {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* 某个 agent preset 对应的模式 id——**只在映射唯一时**回答(几个模式挂同一份 preset 时返回
|
|
386
|
+
* `undefined`,不反查)。
|
|
387
|
+
*
|
|
388
|
+
* 本部署的两个模式共享同一个 preset(`MODE_PRESET_ID`),差异全在会话级收口,所以 preset → 模式的反查在
|
|
389
|
+
* 这里无意义:模式由**会话事实**决定(`session-mode/selected` 投影 → 子代理继承 → 部署默认),
|
|
390
|
+
* 官方 roster 选了什么 preset 不改变这个会话是哪个模式。这条反查留给"一对一映射"的部署形态。
|
|
391
|
+
* @param preset - preset id(`undefined` 表示没选过、或 registry 没装)。
|
|
392
|
+
* @returns 该 preset 唯一对应的模式 id;没配扩展、或由多个模式共享时 `undefined`。
|
|
393
|
+
*/
|
|
394
|
+
modeForPreset(preset) {
|
|
395
|
+
if (preset === void 0) return void 0;
|
|
396
|
+
const owners = Object.keys(this.config.modes).filter((id) => this.config.modes[id]?.preset === preset);
|
|
397
|
+
return owners.length === 1 ? owners[0] : void 0;
|
|
398
|
+
}
|
|
245
399
|
/** 子代理(有 durable 父会话)继承父当前模式;父不在场、或不是子代理时没有可继承的。 */
|
|
246
400
|
inheritedModeId(agent) {
|
|
247
401
|
const parentId = agent.session.header.parentSession;
|
|
@@ -265,18 +419,16 @@ var SessionModes = class extends Service {
|
|
|
265
419
|
this.toolScope()?.apply(agent, mode);
|
|
266
420
|
}
|
|
267
421
|
/**
|
|
268
|
-
*
|
|
422
|
+
* 模式的默认模型(`modes.<模式 id>.defaultModel`)兜底:只在会话**尚无任何模型事实**(没选过模型、也
|
|
269
423
|
* 还没跑过请求)时接管这一请求的路由;一旦用户选过(投影 `pending`)或会话已经落过 header,就不再插手。
|
|
270
424
|
*
|
|
271
|
-
* 它是**配置事实**,不写会话事件——重启后仍由 config
|
|
272
|
-
*
|
|
273
|
-
* 模型取自 `config.models`:那是个 volatile 引用,设置页保存时只有**引用里的值**变,这一行不重挂,
|
|
274
|
-
* 所以每次请求都现场 `.get()`(与 `llm-openai-compatible` 读 `config.providers` 同一种读法)。
|
|
425
|
+
* 它是**配置事实**,不写会话事件——重启后仍由 config 决定;设置页里那条会话级选择才是会话事实。读的是构造
|
|
426
|
+
* 时那份模式清单快照:设置页保存会让这一行重挂(`reconcileProfilePatches`),新定义随重挂生效。
|
|
275
427
|
*/
|
|
276
428
|
installDefaultModel(agent, modeId) {
|
|
277
429
|
return agent.ctx.on("agent/request", async (_payload, next) => {
|
|
278
430
|
const resolved = await next();
|
|
279
|
-
const model = this.config.
|
|
431
|
+
const model = this.config.modes[modeId]?.defaultModel;
|
|
280
432
|
if (model === void 0) return resolved;
|
|
281
433
|
const pending = this.ctx.sessionProjections.stateOf(agent.session, "modelSelection")?.pending;
|
|
282
434
|
if (pending !== void 0 && pending !== null) return resolved;
|
|
@@ -365,4 +517,4 @@ function registerHttpRoutes(ctx, modes) {
|
|
|
365
517
|
});
|
|
366
518
|
}
|
|
367
519
|
//#endregion
|
|
368
|
-
export { Config, SESSION_MODE_PATH, SessionModes, apply, inject, name, sessionModeProjection };
|
|
520
|
+
export { Config, SESSION_MODE_PATH, SessionModes, apply, inject, name, sessionModeEditableProjection, sessionModeProjection };
|
package/dist/rows.d.cts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//#region src/mode-sources.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* 模式定义的真源:`session-mode` 行的 `config` 由 `./rows.ts` 渲染(装配入口在 `packages/bundles/session-mode-profile`)。
|
|
4
|
+
*
|
|
5
|
+
* "自定义"就落在这份数据上——装配层(profile 的用户 patch 层)可以整体改写 `config.modes`,也可以只给
|
|
6
|
+
* 某个模式换提示词或工具白名单,不需要任何插件行。
|
|
7
|
+
*
|
|
8
|
+
* `allowTools` 从 [`@morlay/dsh-agent-toolkit/rows`](../../../dsh-agent-toolkit/src/rows.ts) 的
|
|
9
|
+
* `TOOLKIT_TOOL_NAMES` 派生(工具名与汉化同源):**行清单由本部署自己注册的那份 preset 提供**
|
|
10
|
+
* ({@link MODE_PRESET_ID},两个模式共享它),白名单里那份 preset 没有的工具自动跳过。想改某一个模式的名单,
|
|
11
|
+
* 直接在这条源数据里加/减。
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* 本部署自己注册的那份 agent preset 的 id:两个模式共享它(行清单见
|
|
15
|
+
* `packages/bundles/session-mode-profile`,`config.plugins` 引用 `@morlay/dsh-agent-toolkit/rows` 的
|
|
16
|
+
* `TOOLKIT_PRESET_ROWS`)。
|
|
17
|
+
*
|
|
18
|
+
* 为什么自己注册而不是复用官方 preset:官方 `minimal` 没有 `tool-web`,`chat` 的白名单(提问 + 联网三件)
|
|
19
|
+
* 收口后一件都不剩;而且官方 preset 自带的上游注入要在我们的开关之外做"让位",抢 `skill` 面还得把目录 kind
|
|
20
|
+
* 换掉。行清单归我们之后,两个模式的**差异全在会话级收口**(persona / `allowTools` / 两个开关)。
|
|
21
|
+
*/
|
|
22
|
+
declare const MODE_PRESET_ID = "mode-switch";
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/rows.d.ts
|
|
25
|
+
/** 一行装配条目:与 `cordis.patch.yml` 的顶层结构同形。 */
|
|
26
|
+
interface PatchRow {
|
|
27
|
+
readonly insert?: readonly RowEntry[];
|
|
28
|
+
}
|
|
29
|
+
/** `insert` 里的一个条目。 */
|
|
30
|
+
interface RowEntry {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly config?: Readonly<Record<string, unknown>>;
|
|
34
|
+
}
|
|
35
|
+
/** `session-mode` 行的装配:默认模式与各模式的扩展定义。 */
|
|
36
|
+
declare function sessionModeRows(): readonly PatchRow[];
|
|
37
|
+
//#endregion
|
|
38
|
+
export { MODE_PRESET_ID, PatchRow, RowEntry, sessionModeRows };
|
package/dist/rows.d.mts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//#region src/mode-sources.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* 模式定义的真源:`session-mode` 行的 `config` 由 `./rows.ts` 渲染(装配入口在 `packages/bundles/session-mode-profile`)。
|
|
4
|
+
*
|
|
5
|
+
* "自定义"就落在这份数据上——装配层(profile 的用户 patch 层)可以整体改写 `config.modes`,也可以只给
|
|
6
|
+
* 某个模式换提示词或工具白名单,不需要任何插件行。
|
|
7
|
+
*
|
|
8
|
+
* `allowTools` 从 [`@morlay/dsh-agent-toolkit/rows`](../../../dsh-agent-toolkit/src/rows.ts) 的
|
|
9
|
+
* `TOOLKIT_TOOL_NAMES` 派生(工具名与汉化同源):**行清单由本部署自己注册的那份 preset 提供**
|
|
10
|
+
* ({@link MODE_PRESET_ID},两个模式共享它),白名单里那份 preset 没有的工具自动跳过。想改某一个模式的名单,
|
|
11
|
+
* 直接在这条源数据里加/减。
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* 本部署自己注册的那份 agent preset 的 id:两个模式共享它(行清单见
|
|
15
|
+
* `packages/bundles/session-mode-profile`,`config.plugins` 引用 `@morlay/dsh-agent-toolkit/rows` 的
|
|
16
|
+
* `TOOLKIT_PRESET_ROWS`)。
|
|
17
|
+
*
|
|
18
|
+
* 为什么自己注册而不是复用官方 preset:官方 `minimal` 没有 `tool-web`,`chat` 的白名单(提问 + 联网三件)
|
|
19
|
+
* 收口后一件都不剩;而且官方 preset 自带的上游注入要在我们的开关之外做"让位",抢 `skill` 面还得把目录 kind
|
|
20
|
+
* 换掉。行清单归我们之后,两个模式的**差异全在会话级收口**(persona / `allowTools` / 两个开关)。
|
|
21
|
+
*/
|
|
22
|
+
declare const MODE_PRESET_ID = "mode-switch";
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/rows.d.ts
|
|
25
|
+
/** 一行装配条目:与 `cordis.patch.yml` 的顶层结构同形。 */
|
|
26
|
+
interface PatchRow {
|
|
27
|
+
readonly insert?: readonly RowEntry[];
|
|
28
|
+
}
|
|
29
|
+
/** `insert` 里的一个条目。 */
|
|
30
|
+
interface RowEntry {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly name: string;
|
|
33
|
+
readonly config?: Readonly<Record<string, unknown>>;
|
|
34
|
+
}
|
|
35
|
+
/** `session-mode` 行的装配:默认模式与各模式的扩展定义。 */
|
|
36
|
+
declare function sessionModeRows(): readonly PatchRow[];
|
|
37
|
+
//#endregion
|
|
38
|
+
export { MODE_PRESET_ID, PatchRow, RowEntry, sessionModeRows };
|