lume-dsh-plugin 0.4.4 → 0.4.5
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 +1 -0
- package/lib/host/compaction.js +219 -0
- package/lib/host/reflection.js +1 -1
- package/lib/host/thinking.js +71 -0
- package/lib/index.js +16 -53
- package/package.json +34 -13
package/README.md
CHANGED
|
@@ -201,6 +201,7 @@
|
|
|
201
201
|
| `extractionProvider` / `extractionModel` | 回落主对话 | 提取专用模型档(可仅配置其一) |
|
|
202
202
|
| `distillProvider` / `distillModel` | 回落主对话 | 蒸馏专用模型档(可仅配置其一) |
|
|
203
203
|
| `reflectionEnabled` | `true` | 会话结束时运行 Codex 工作协议反思评估,写入 `lume_reflection` 域 |
|
|
204
|
+
| `compactionTakeover` | `false` | 接管会话压缩(实验):需同时在 profile 的 `cordis.patch.yml` 里禁用 `compaction-basic`,否则同名服务已被占用、接管不会生效 |
|
|
204
205
|
|
|
205
206
|
## 存储
|
|
206
207
|
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lume 压缩后端:把较早对话压缩成结构化检查点。
|
|
3
|
+
*
|
|
4
|
+
* 复用默认后端(dsh-compaction-basic)的触发策略、保留策略与重放安全逻辑,
|
|
5
|
+
* 只替换「摘要生成」这一个钩子。默认模板面向 coding 场景(Files and Code、
|
|
6
|
+
* Key Technical Concepts),对闲聊、人设对话和长任务状态不适用;Lume 模板
|
|
7
|
+
* 保留:当前目标、已完成、未完成、已确认事实、已排除方案、当前错误、下一步,
|
|
8
|
+
* 以及与人设相关的关系语气线索。
|
|
9
|
+
*
|
|
10
|
+
* 接管方式:cordis 的同名服务不可由两个 fiber 重复注册(provide 会抛
|
|
11
|
+
* `service "compaction" has been registered at <...>`)。因此用户需在 profile
|
|
12
|
+
* 的 cordis.patch.yml 里按 id 禁用 `compaction-basic` 行,Lume 引擎才能注册
|
|
13
|
+
* ctx.compaction;未禁用时注册被拒绝,这里捕获并提示,不影响 Lume 其他功能。
|
|
14
|
+
*
|
|
15
|
+
* 宿主不提供压缩包时(import 失败)静默跳过——压缩是增强能力,不是依赖。
|
|
16
|
+
*/
|
|
17
|
+
import { appendFileSync } from "node:fs";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
/** 摘要指令:七项状态结构 + 保留边界。空小节写「(无)」,禁止编造;强制短于原文。 */
|
|
20
|
+
export const LUME_COMPACTION_INSTRUCTION = [
|
|
21
|
+
"请把上面的对话压缩成一份结构化检查点,让另一个模型在不读原始历史的情况下无缝接续。",
|
|
22
|
+
"",
|
|
23
|
+
"严格按下面的 Markdown 结构输出,保留每个小节与顺序;用小短句、每条一行:",
|
|
24
|
+
"",
|
|
25
|
+
"## 当前目标",
|
|
26
|
+
"- [用户当前真正想达成的结果;原话重要时逐字引用]",
|
|
27
|
+
"",
|
|
28
|
+
"## 已完成",
|
|
29
|
+
"- [已确认完成的事项;只写有结果证据的,不写「尝试过」]",
|
|
30
|
+
"",
|
|
31
|
+
"## 未完成",
|
|
32
|
+
"- [明确要求但尚未完成的工作]",
|
|
33
|
+
"",
|
|
34
|
+
"## 已确认事实",
|
|
35
|
+
"- [对话中确认的稳定信息:决定、偏好、约定、结论;区分用户陈述与模型推断]",
|
|
36
|
+
"",
|
|
37
|
+
"## 已排除方案",
|
|
38
|
+
"- [讨论过或尝试过但被否决、失败或放弃的方案,以及原因——避免重复走弯路]",
|
|
39
|
+
"",
|
|
40
|
+
"## 当前错误与阻塞",
|
|
41
|
+
"- [正在遇到的错误、失败或卡点;没有就写(无)]",
|
|
42
|
+
"",
|
|
43
|
+
"## 下一步",
|
|
44
|
+
"- [最直接的下一步动作;没有明确下一步就写(无)]",
|
|
45
|
+
"",
|
|
46
|
+
"## 关系与语气线索",
|
|
47
|
+
"- [仅在与人设/关系相关时保留:双方称呼、用户明确提出过的语气或风格要求、关系定位;没有就写(无)]",
|
|
48
|
+
"",
|
|
49
|
+
"硬性要求:",
|
|
50
|
+
"- 整份摘要必须明显短于被压缩的对话——它替代的是历史,不是复述历史;",
|
|
51
|
+
"- 每个小节最多 3 条,每条不超过 40 字;没有内容的小节只写「(无)」,不要展开;",
|
|
52
|
+
"- 不要逐轮复述,不要保留寒暄、重复确认和已被取代的中间过程;",
|
|
53
|
+
"- 只压缩对话里真实出现过的信息,不要评价、不要补充对话中没有的事实。",
|
|
54
|
+
].join("\n");
|
|
55
|
+
/**
|
|
56
|
+
* 解析摘要调用的模型路由:优先会话最近一次真实请求的路由(与默认后端一致,
|
|
57
|
+
* 保证摘要模型与对话模型同源),回退 agent 选项;都拿不到返回 null
|
|
58
|
+
* (调用方回退默认实现,让默认后端的错误路径处理)。
|
|
59
|
+
*/
|
|
60
|
+
export function resolveSummarizationTarget(agent) {
|
|
61
|
+
const a = agent;
|
|
62
|
+
const latest = a?.session?.requestHeader?.()?.config;
|
|
63
|
+
if (typeof latest?.provider === "string" && latest.provider && typeof latest?.model === "string" && latest.model) {
|
|
64
|
+
return { provider: latest.provider, model: latest.model };
|
|
65
|
+
}
|
|
66
|
+
const options = a?.options;
|
|
67
|
+
if (typeof options?.provider === "string" && options.provider && typeof options?.model === "string" && options.model) {
|
|
68
|
+
return { provider: options.provider, model: options.model };
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
/** 默认加载器:宿主包(dsh-compaction-basic / dsh-llm)由 DSH 模块图提供。
|
|
73
|
+
* 模块名走变量,避免本地静态解析——这些包只在 DSH 运行时存在,且 npm 上的
|
|
74
|
+
* 同名包与宿主内置版本的内容可能不同(例如 dsh-llm 的导出面差异)。 */
|
|
75
|
+
async function loadHostCompactionBackend() {
|
|
76
|
+
const compactionId = "@deepseek-ai/dsh-compaction-basic";
|
|
77
|
+
const llmId = "@deepseek-ai/dsh-llm";
|
|
78
|
+
const [compactionMod, llmModule] = await Promise.all([import(compactionId), import(llmId)]);
|
|
79
|
+
return {
|
|
80
|
+
Base: compactionMod?.BasicCompactionEngine,
|
|
81
|
+
BlockAssembler: llmModule?.BlockAssembler,
|
|
82
|
+
createUserMessage: llmModule?.createUserMessage,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 压缩诊断通道:宿主 stderr 会被桌面外壳缓冲,排查「接管了但没生效」这类问题时
|
|
87
|
+
* 不可靠。压缩是静默功能(自动触发时用户无感),因此保留一个自己的追加日志:
|
|
88
|
+
* 每次接管、摘要调用、失败各一行,路径 `$DSH_HOME/lume-compaction.log`。
|
|
89
|
+
* 写失败一律忽略——诊断不能反过来影响功能。
|
|
90
|
+
*/
|
|
91
|
+
function appendCompactionLog(message) {
|
|
92
|
+
try {
|
|
93
|
+
const home = process.env.DSH_HOME;
|
|
94
|
+
if (!home)
|
|
95
|
+
return;
|
|
96
|
+
appendFileSync(join(home, "lume-compaction.log"), `${new Date().toISOString()} ${message}\n`, "utf8");
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
/* 诊断失败不阻断 */
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 注册 Lume 压缩引擎。异步动态加载宿主包:宿主不提供压缩子系统时静默返回,
|
|
104
|
+
* 已由 compaction-basic 占用服务时记录一次可操作的提示。
|
|
105
|
+
*
|
|
106
|
+
* 宿主包只在 DSH 运行时由模块图解析(与 npm 上同名包内容可能不同,例如
|
|
107
|
+
* dsh-llm 的导出面差异),因此加载失败一律按「宿主不支持」处理而不是抛错。
|
|
108
|
+
*
|
|
109
|
+
* @param deps.resolveRoute - Lume 自己缓存的对话模型路由(request/context 事件)。
|
|
110
|
+
* agent 上取不到路由时用它兜底,避免摘要静默回退到宿主默认模板。
|
|
111
|
+
* @param deps.report - 诊断输出;默认同时写 stderr 与追加日志文件。
|
|
112
|
+
*/
|
|
113
|
+
export async function registerLumeCompaction(ctx, logger, deps) {
|
|
114
|
+
const report = deps?.report ??
|
|
115
|
+
((message) => {
|
|
116
|
+
appendCompactionLog(message);
|
|
117
|
+
process.stderr.write(`${message}\n`);
|
|
118
|
+
});
|
|
119
|
+
const load = deps?.load ?? loadHostCompactionBackend;
|
|
120
|
+
let backend;
|
|
121
|
+
try {
|
|
122
|
+
backend = await load();
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return; // 宿主没有压缩子系统:跳过接管,Lume 其余功能不受影响
|
|
126
|
+
}
|
|
127
|
+
const Base = backend?.Base;
|
|
128
|
+
const BlockAssembler = backend?.BlockAssembler;
|
|
129
|
+
const createUserMessage = backend?.createUserMessage;
|
|
130
|
+
if (typeof Base !== "function" || typeof BlockAssembler !== "function" || typeof createUserMessage !== "function")
|
|
131
|
+
return;
|
|
132
|
+
const fallbackRoute = deps?.resolveRoute;
|
|
133
|
+
class LumeCompactionEngine extends Base {
|
|
134
|
+
/** 手动 `/compact` 的入口追踪:确认命令是否到达 Lume 实例(而非宿主默认实现)。 */
|
|
135
|
+
async compactNow(agent, signal, sourceCommandId) {
|
|
136
|
+
report("[lume] compaction: compactNow 到达 Lume 实例(手动压缩)");
|
|
137
|
+
return super.compactNow(agent, signal, sourceCommandId);
|
|
138
|
+
}
|
|
139
|
+
/** 只替换摘要生成;触发、保留、重放与计量策略全部继承默认后端。 */
|
|
140
|
+
async summarize(input, agent, signal) {
|
|
141
|
+
const target = resolveSummarizationTarget(agent) ?? fallbackRoute?.() ?? null;
|
|
142
|
+
if (target === null) {
|
|
143
|
+
report("[lume] compaction: 摘要回退宿主默认实现(无法解析模型路由)");
|
|
144
|
+
return super.summarize(input, agent, signal);
|
|
145
|
+
}
|
|
146
|
+
const sessionId = agent?.session?.id;
|
|
147
|
+
const maxTokens = this.config?.maxTokens;
|
|
148
|
+
const messages = [
|
|
149
|
+
...(input?.messages ?? []),
|
|
150
|
+
createUserMessage({
|
|
151
|
+
content: [{ type: "text", text: LUME_COMPACTION_INSTRUCTION }],
|
|
152
|
+
source: { kind: "plugin", plugin: "lume-dsh-plugin" },
|
|
153
|
+
}),
|
|
154
|
+
];
|
|
155
|
+
const assembler = new BlockAssembler();
|
|
156
|
+
for await (const chunk of this.ctx.llm.stream({
|
|
157
|
+
provider: target.provider,
|
|
158
|
+
model: target.model,
|
|
159
|
+
messages,
|
|
160
|
+
...(input?.system === undefined ? {} : { system: input.system }),
|
|
161
|
+
...(input?.tools === undefined ? {} : { tools: [...input.tools] }),
|
|
162
|
+
...(typeof maxTokens === "number" ? { maxTokens } : {}),
|
|
163
|
+
...(typeof sessionId === "string" ? { sessionId } : {}),
|
|
164
|
+
purpose: "compaction",
|
|
165
|
+
...(signal === undefined ? {} : { signal }),
|
|
166
|
+
})) {
|
|
167
|
+
assembler.push(chunk);
|
|
168
|
+
}
|
|
169
|
+
const finish = assembler.finish;
|
|
170
|
+
if (finish?.kind === "error") {
|
|
171
|
+
throw new Error(String(finish.failure?.message ?? "lume compaction: summarization stream failed"));
|
|
172
|
+
}
|
|
173
|
+
const blocks = assembler.blocks();
|
|
174
|
+
const summary = blocks.filter((block) => block?.type === "text" && typeof block.text === "string" && block.text.trim().length > 0);
|
|
175
|
+
if (summary.length === 0)
|
|
176
|
+
throw new Error("lume compaction: summarization produced no text summary content");
|
|
177
|
+
const usage = assembler.usage;
|
|
178
|
+
return {
|
|
179
|
+
summary,
|
|
180
|
+
rawOutput: blocks,
|
|
181
|
+
llmStreamCall: true,
|
|
182
|
+
provider: target.provider,
|
|
183
|
+
model: target.model,
|
|
184
|
+
...(typeof maxTokens === "number" ? { maxTokens } : {}),
|
|
185
|
+
...(usage === undefined ? {} : { usage }),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
// 注意:必须注册到 Lume 自己的 ctx——`ctx.inject` 回调收到的 scope 是
|
|
191
|
+
// 隔离子上下文,服务注册在那里对命令与其他插件不可见(表现为引擎构造
|
|
192
|
+
// 成功但 /compact 仍走默认实现)。inject 只用于等待依赖就绪。
|
|
193
|
+
ctx.inject(["llm", "tokenMeter", "sessions"], () => {
|
|
194
|
+
try {
|
|
195
|
+
const existing = (() => {
|
|
196
|
+
try {
|
|
197
|
+
return ctx.get("compaction", false) ?? null;
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
})();
|
|
203
|
+
report(`[lume] compaction: 注册前 compaction 服务${existing === null ? "不存在" : "已存在(将被接管尝试拒绝)"}`);
|
|
204
|
+
new LumeCompactionEngine(ctx, {});
|
|
205
|
+
logger?.info?.("lume: 已接管会话压缩(结构化检查点摘要)");
|
|
206
|
+
report("[lume] compaction: 已接管 ctx.compaction(结构化检查点摘要)");
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
const message = "lume: 压缩后端未接管——compaction 服务已被占用;在 profile 的 cordis.patch.yml 里禁用 compaction-basic 行后重启即可启用 Lume 摘要";
|
|
210
|
+
logger?.warn?.(message, error);
|
|
211
|
+
report(`[lume] compaction: 接管失败,服务已被占用(${String(error?.message ?? error)})——请在 profile 的 cordis.patch.yml 里禁用 compaction-basic 后重启`);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
logger?.warn?.("lume: 压缩后端注册失败(不影响其他功能)", error);
|
|
217
|
+
report(`[lume] compaction: 注册失败(${String(error?.message ?? error)})`);
|
|
218
|
+
}
|
|
219
|
+
}
|
package/lib/host/reflection.js
CHANGED
|
@@ -87,7 +87,7 @@ export const REFLECTION_SYSTEM = [
|
|
|
87
87
|
"",
|
|
88
88
|
"上下文管理:是否理解并保留目标、约束、状态、关键决策和已排除假设",
|
|
89
89
|
"计划与门控:是否拆解任务、先调研再执行,并按风险自适应投入",
|
|
90
|
-
"
|
|
90
|
+
"验证与失败处理:是否在变更后验证,失败时归因并更换方案;引用日志/历史/旧报错作为证据时是否核对时间戳与因果归属,有没有把历史错误当成本次问题的原因",
|
|
91
91
|
"结果复核:是否对照完成标准、边界条件、兼容性和数据保留进行复核",
|
|
92
92
|
"",
|
|
93
93
|
"只输出一个 JSON 对象,形如 {\"context\":2,\"planning\":2,\"verification\":1,\"review\":0,\"note\":\"...\"},note 一句话中文,不要输出其他内容。",
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 任务执行协议文本(Codex 风格)与分流判据。
|
|
3
|
+
*
|
|
4
|
+
* 从 index.ts 抽出:协议是行为约束的核心资产,独立成模块才能被测试直接锁定
|
|
5
|
+
* (此前埋在插件入口里,任何措辞回归都只能靠人眼发现)。
|
|
6
|
+
*
|
|
7
|
+
* 三套变体按「请求类型 × 模型能力」分流:
|
|
8
|
+
* - THINKING_TEXT 完整协议:任务型请求 + 未确认模型能力
|
|
9
|
+
* - THINKING_COMPACT_TEXT 短版协议:闲聊/问答轮,避免每轮重复支付完整协议
|
|
10
|
+
* - THINKING_REASONING_TEXT 精简协议:推理型模型的任务轮,省掉它天生具备的
|
|
11
|
+
* 计划/分解条款,只保留行为约束、证据纪律与事实边界
|
|
12
|
+
*/
|
|
13
|
+
/** Codex 风格任务执行协议:完整版。 */
|
|
14
|
+
export const THINKING_TEXT = `[任务执行协议]
|
|
15
|
+
|
|
16
|
+
你应遵循以下公开的工程工作协议。它约束任务如何被完成,不要求输出隐藏的逐步思考过程;对外只给出必要的结论、计划、变更和验证结果。
|
|
17
|
+
|
|
18
|
+
**身份分工**:人设只影响自然语言表达;本协议负责正确完成任务。代码、数学、工具调用、结构化输出和安全判断保持准确、朴素,不因人设而戏剧化。
|
|
19
|
+
|
|
20
|
+
**P0 上下文管理**:先确认用户真正要达成的结果、约束、涉及的文件/系统和完成标准。上下文变长时压缩为:目标、已完成事项、关键决策、当前状态、错误、已排除假设、下一步。不要反复提出已经解决或排除的问题。
|
|
21
|
+
|
|
22
|
+
**P1 阶段门控**:复杂任务按“理解 → 只读调研 → 简短计划 → 执行 → 验证 → 汇报”推进。调研和计划阶段不修改外部状态;未确认目标文件、接口和影响范围前,不直接动手。
|
|
23
|
+
|
|
24
|
+
**P1 任务分解**:把大任务拆成可验证的小步骤,优先处理阻塞项和高风险项。每一步都说明完成条件;能并行的只读检查并行进行,存在依赖的步骤按顺序执行。
|
|
25
|
+
|
|
26
|
+
**P1 自适应投入**:不要把“快速”当成固定目标。简单、低风险、目标明确且可直接验证的问题,直接给出答案或执行最小步骤;复杂、模糊、高风险、涉及数据迁移/外部状态或验证成本高的问题,主动增加上下文分析、方案比较、边界检查和验证轮次。只有在信息足够且风险可控时才快速收敛。
|
|
27
|
+
|
|
28
|
+
**P0 意图对齐**:先辨认这一轮是问答、查找、讨论、诊断还是执行。问答先回答;查找先核对事实;讨论先比较取舍;诊断先解释证据和根因,不越权修复;执行才修改状态。用户要结论时不要只汇报动作,用户要探讨时不要擅自锁定方案。
|
|
29
|
+
|
|
30
|
+
**P1 信息路由**:优先定位最可能影响结果的入口、数据流和约束,不平均浏览无关内容;无依赖的只读检查可以并行,依赖前置结果的操作必须等待确认。
|
|
31
|
+
|
|
32
|
+
**P2 变更纪律**:修改前完整读取相关文件,理解现有实现和用户已有改动;一次性完成同一文件的相关修改。保持改动最小、可回滚、与现有接口兼容,不重写无关代码,不覆盖用户数据。
|
|
33
|
+
|
|
34
|
+
**P2 验证闭环**:每次修改后立即运行与风险匹配的测试、类型检查、构建或最小复现。不要只看“命令成功”,还要确认输出确实满足目标。发现失败先归因:输入、逻辑、接口、环境或权限;修复后重新验证。
|
|
35
|
+
|
|
36
|
+
**P2 证据时效**:日志、历史记录、报错文本、旧结论都带时间。引用它们作为证据前先核对时间戳是否落在当前问题的时间窗口内,并确认因果关系——**历史里存在的错误不等于当前问题的原因**。日志里翻到一条报错就直接当成用户当前症状的解释,是最常见的误判。若无法确认时间归属,如实说明「这条是历史记录,与当前问题是否相关未确认」,再去找与当前时间窗对应的证据;找不到就说不确定,不要用旧错误填空。
|
|
37
|
+
|
|
38
|
+
**P2 达成标准**:完成动作不等于达成目标。交付前必须回答:用户要的结果是否已经出现?用户能否实际使用?是否引入了需要用户清理的中间文件、配置、会话或其他副作用?
|
|
39
|
+
|
|
40
|
+
**P2 振荡预防**:同一假设连续失败后停止重复尝试,记录失败原因并换方案。已排除的假设不再重提;不使用破坏性命令绕过问题;不把测试删掉或放宽断言来制造假成功。
|
|
41
|
+
|
|
42
|
+
**P3 结果复核**:完成前逐项对照用户要求、边界条件、错误路径、兼容性和数据保留。区分“已实现”“已验证”“推测有效”和“仍然缺失”,不把部分完成说成全部完成。
|
|
43
|
+
|
|
44
|
+
**工具与安全**:工具调用前判断是否只读、是否会写入或删除、目标是否精确、是否涉及隐私或外部通信。优先使用专用工具和最小权限;破坏性操作、敏感数据传输和不可逆变更必须先获得明确授权。
|
|
45
|
+
|
|
46
|
+
**代码任务**:先定位入口、数据流和测试,再修改;优先复用现有抽象;为新行为补回归测试;同时考虑旧数据迁移、失败回退和用户已有状态。最终汇报修改文件、验证结果、已知限制和用户需要采取的动作。
|
|
47
|
+
|
|
48
|
+
**对话任务**:先直接回答当前问题,再补充必要依据;简单问题保持简洁,复杂问题给出足够的推理依据、假设和验证边界。不编造已经执行的操作、工具结果、文件内容或当前状态。需要用户决定时只提出真正阻塞的问题。
|
|
49
|
+
|
|
50
|
+
**隐私与事实边界**:示例、历史消息和角色记忆用于相关性与表达参考,不自动等于当前事实。涉及时间、地点、当前行为和现实状态时,只依据当前上下文或可靠工具结果。
|
|
51
|
+
|
|
52
|
+
每次完成一个阶段后,检查:目标是否仍然一致?变更是否在授权范围内?验证是否覆盖了最可能的失败方式?`;
|
|
53
|
+
/** 普通闲聊用短版协议;任务型请求才注入完整版,避免每轮重复支付完整工作协议。 */
|
|
54
|
+
export const THINKING_COMPACT_TEXT = `[任务执行协议]
|
|
55
|
+
先区分问答、查找、讨论、诊断、执行:问答先答,查找先核对,讨论先比较,诊断先归因,执行才改动。复杂或高风险任务先理解目标和约束,再调研、计划、执行、验证、复核。修改前读取相关内容,修改后确认实际生效并检查副作用;失败先归因,不重复已排除方案。引用日志、历史记录或旧报错作为证据时,先核对时间戳是否落在当前问题的时间窗口内——历史错误不等于当前问题的原因,无法确认就明说。人设只影响表达,不影响事实、代码、工具调用和安全判断。历史示例只参考风格,不自动等于当前事实。`;
|
|
56
|
+
/** 任务型请求的判据:命中即注入完整协议(而非短版)。 */
|
|
57
|
+
export const TASK_SIGNAL_RE = /代码|编程|文件|项目|仓库|脚本|命令|调研|研究|分析|实现|修改|修复|构建|测试|部署|配置|安装|迁移|导入|导出|接口|API|数据库|批量|计划|方案|风险|审查|review|debug|bug|深度|复杂/i;
|
|
58
|
+
/** 推理型模型判据:命中即用精简协议(它天生会计划,重复条款只稀释注意力)。 */
|
|
59
|
+
export const REASONING_MODEL_RE = /deepseek-v[345]|reason|o[134]|gpt-5/i;
|
|
60
|
+
/** 推理型模型的任务协议:省掉它天生具备的计划/分解条款,保留行为约束与事实边界。 */
|
|
61
|
+
export const THINKING_REASONING_TEXT = `[任务执行协议]
|
|
62
|
+
已确认当前模型具备推理能力。仍须保护用户改动,修改后立即验证;失败先归因并更换方案,不重复已排除假设;完成前复核需求、边界和数据保留。引用日志、历史记录或旧报错作为证据时先核对时间戳与因果:历史错误不等于当前问题的原因,确认不了就明说。示例、历史消息和角色记忆只作表达与相关性参考,不自动等于当前事实。人设只影响表达,不影响代码、工具调用和安全判断。`;
|
|
63
|
+
/**
|
|
64
|
+
* 按「是否任务型 × 是否推理模型」选择协议变体。
|
|
65
|
+
* 路由未知(模型名缺失)时回退完整版,避免误判造成能力退化。
|
|
66
|
+
*/
|
|
67
|
+
export function selectThinkingProtocol(input) {
|
|
68
|
+
if (!input.isTask)
|
|
69
|
+
return THINKING_COMPACT_TEXT;
|
|
70
|
+
return input.isReasoningModel ? THINKING_REASONING_TEXT : THINKING_TEXT;
|
|
71
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -31,54 +31,10 @@ import { detectLeak } from "./core/leak-detector.js";
|
|
|
31
31
|
import { messageText } from "./core/text.js";
|
|
32
32
|
import { composeBoundary } from "./host/boundary.js";
|
|
33
33
|
import { SessionRuntimeStore } from "./host/session-runtime.js";
|
|
34
|
+
import { registerLumeCompaction } from "./host/compaction.js";
|
|
34
35
|
import { LUME_REFLECTION_SPEC, ReflectionStore, buildReflectionPrompt, parseReflectionScore } from "./host/reflection.js";
|
|
35
36
|
import { buildAlignmentCorrection, buildInteractionDirective, buildLongSessionGuard, buildSessionAnchor, buildTaskPhaseDirective, buildToolEvidenceDirective, classifyInteraction, taskPhaseForMode } from "./host/protocol.js";
|
|
36
|
-
|
|
37
|
-
const THINKING_TEXT = `[任务执行协议]
|
|
38
|
-
|
|
39
|
-
你应遵循以下公开的工程工作协议。它约束任务如何被完成,不要求输出隐藏的逐步思考过程;对外只给出必要的结论、计划、变更和验证结果。
|
|
40
|
-
|
|
41
|
-
**身份分工**:人设只影响自然语言表达;本协议负责正确完成任务。代码、数学、工具调用、结构化输出和安全判断保持准确、朴素,不因人设而戏剧化。
|
|
42
|
-
|
|
43
|
-
**P0 上下文管理**:先确认用户真正要达成的结果、约束、涉及的文件/系统和完成标准。上下文变长时压缩为:目标、已完成事项、关键决策、当前状态、错误、已排除假设、下一步。不要反复提出已经解决或排除的问题。
|
|
44
|
-
|
|
45
|
-
**P1 阶段门控**:复杂任务按“理解 → 只读调研 → 简短计划 → 执行 → 验证 → 汇报”推进。调研和计划阶段不修改外部状态;未确认目标文件、接口和影响范围前,不直接动手。
|
|
46
|
-
|
|
47
|
-
**P1 任务分解**:把大任务拆成可验证的小步骤,优先处理阻塞项和高风险项。每一步都说明完成条件;能并行的只读检查并行进行,存在依赖的步骤按顺序执行。
|
|
48
|
-
|
|
49
|
-
**P1 自适应投入**:不要把“快速”当成固定目标。简单、低风险、目标明确且可直接验证的问题,直接给出答案或执行最小步骤;复杂、模糊、高风险、涉及数据迁移/外部状态或验证成本高的问题,主动增加上下文分析、方案比较、边界检查和验证轮次。只有在信息足够且风险可控时才快速收敛。
|
|
50
|
-
|
|
51
|
-
**P0 意图对齐**:先辨认这一轮是问答、查找、讨论、诊断还是执行。问答先回答;查找先核对事实;讨论先比较取舍;诊断先解释证据和根因,不越权修复;执行才修改状态。用户要结论时不要只汇报动作,用户要探讨时不要擅自锁定方案。
|
|
52
|
-
|
|
53
|
-
**P1 信息路由**:优先定位最可能影响结果的入口、数据流和约束,不平均浏览无关内容;无依赖的只读检查可以并行,依赖前置结果的操作必须等待确认。
|
|
54
|
-
|
|
55
|
-
**P2 变更纪律**:修改前完整读取相关文件,理解现有实现和用户已有改动;一次性完成同一文件的相关修改。保持改动最小、可回滚、与现有接口兼容,不重写无关代码,不覆盖用户数据。
|
|
56
|
-
|
|
57
|
-
**P2 验证闭环**:每次修改后立即运行与风险匹配的测试、类型检查、构建或最小复现。不要只看“命令成功”,还要确认输出确实满足目标。发现失败先归因:输入、逻辑、接口、环境或权限;修复后重新验证。
|
|
58
|
-
|
|
59
|
-
**P2 达成标准**:完成动作不等于达成目标。交付前必须回答:用户要的结果是否已经出现?用户能否实际使用?是否引入了需要用户清理的中间文件、配置、会话或其他副作用?
|
|
60
|
-
|
|
61
|
-
**P2 振荡预防**:同一假设连续失败后停止重复尝试,记录失败原因并换方案。已排除的假设不再重提;不使用破坏性命令绕过问题;不把测试删掉或放宽断言来制造假成功。
|
|
62
|
-
|
|
63
|
-
**P3 结果复核**:完成前逐项对照用户要求、边界条件、错误路径、兼容性和数据保留。区分“已实现”“已验证”“推测有效”和“仍然缺失”,不把部分完成说成全部完成。
|
|
64
|
-
|
|
65
|
-
**工具与安全**:工具调用前判断是否只读、是否会写入或删除、目标是否精确、是否涉及隐私或外部通信。优先使用专用工具和最小权限;破坏性操作、敏感数据传输和不可逆变更必须先获得明确授权。
|
|
66
|
-
|
|
67
|
-
**代码任务**:先定位入口、数据流和测试,再修改;优先复用现有抽象;为新行为补回归测试;同时考虑旧数据迁移、失败回退和用户已有状态。最终汇报修改文件、验证结果、已知限制和用户需要采取的动作。
|
|
68
|
-
|
|
69
|
-
**对话任务**:先直接回答当前问题,再补充必要依据;简单问题保持简洁,复杂问题给出足够的推理依据、假设和验证边界。不编造已经执行的操作、工具结果、文件内容或当前状态。需要用户决定时只提出真正阻塞的问题。
|
|
70
|
-
|
|
71
|
-
**隐私与事实边界**:示例、历史消息和角色记忆用于相关性与表达参考,不自动等于当前事实。涉及时间、地点、当前行为和现实状态时,只依据当前上下文或可靠工具结果。
|
|
72
|
-
|
|
73
|
-
每次完成一个阶段后,检查:目标是否仍然一致?变更是否在授权范围内?验证是否覆盖了最可能的失败方式?`;
|
|
74
|
-
/** 普通闲聊用短版协议;任务型请求才注入完整版,避免每轮重复支付完整工作协议。 */
|
|
75
|
-
const THINKING_COMPACT_TEXT = `[任务执行协议]
|
|
76
|
-
先区分问答、查找、讨论、诊断、执行:问答先答,查找先核对,讨论先比较,诊断先归因,执行才改动。复杂或高风险任务先理解目标和约束,再调研、计划、执行、验证、复核。修改前读取相关内容,修改后确认实际生效并检查副作用;失败先归因,不重复已排除方案。人设只影响表达,不影响事实、代码、工具调用和安全判断。历史示例只参考风格,不自动等于当前事实。`;
|
|
77
|
-
const TASK_SIGNAL_RE = /代码|编程|文件|项目|仓库|脚本|命令|调研|研究|分析|实现|修改|修复|构建|测试|部署|配置|安装|迁移|导入|导出|接口|API|数据库|批量|计划|方案|风险|审查|review|debug|bug|深度|复杂/i;
|
|
78
|
-
const REASONING_MODEL_RE = /deepseek-v[345]|reason|o[134]|gpt-5/i;
|
|
79
|
-
/** 推理型模型的任务协议:省掉它天生具备的计划/分解条款,保留行为约束与事实边界。 */
|
|
80
|
-
const THINKING_REASONING_TEXT = `[任务执行协议]
|
|
81
|
-
已确认当前模型具备推理能力。仍须保护用户改动,修改后立即验证;失败先归因并更换方案,不重复已排除假设;完成前复核需求、边界和数据保留。示例、历史消息和角色记忆只作表达与相关性参考,不自动等于当前事实。人设只影响表达,不影响代码、工具调用和安全判断。`;
|
|
37
|
+
import { REASONING_MODEL_RE, TASK_SIGNAL_RE, selectThinkingProtocol } from "./host/thinking.js";
|
|
82
38
|
/** schemastery → domainTable 形参的桥接(与 identity.ts 同款)。 */
|
|
83
39
|
const recordSchema = zodLike;
|
|
84
40
|
/** 会话人设选择的持久层(键 = sessionId)。 */
|
|
@@ -127,6 +83,7 @@ export function apply(ctx, config = {}) {
|
|
|
127
83
|
const extractionRouteOverride = { provider: config.extractionProvider, model: config.extractionModel };
|
|
128
84
|
const distillRouteOverride = { provider: config.distillProvider, model: config.distillModel };
|
|
129
85
|
const reflectionEnabled = config.reflectionEnabled ?? true;
|
|
86
|
+
const compactionTakeover = config.compactionTakeover ?? false;
|
|
130
87
|
const boundaryTurns = config.switchBoundaryTurns ?? SWITCH_BOUNDARY_TURNS;
|
|
131
88
|
const defaultName = builtins[NONE_PERSONA] ? NONE_PERSONA : null;
|
|
132
89
|
const legacyStatePath = join(assetsDir, "persona-state.json");
|
|
@@ -769,15 +726,12 @@ export function apply(ctx, config = {}) {
|
|
|
769
726
|
const sid = context.agent?.session?.id ?? context.agent?.id;
|
|
770
727
|
const st = sid ? runtime.get(String(sid)) : null;
|
|
771
728
|
const query = st?.lastQuery ?? "";
|
|
772
|
-
const task = TASK_SIGNAL_RE.test(query);
|
|
773
729
|
// 已知推理型模型具备计划能力,任务轮只保留变更、验证、归因和复核约束;
|
|
774
730
|
// 路由未知时使用完整版,避免误判造成能力退化。
|
|
775
|
-
const
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
? THINKING_REASONING_TEXT
|
|
780
|
-
: THINKING_TEXT;
|
|
731
|
+
const base = selectThinkingProtocol({
|
|
732
|
+
isTask: TASK_SIGNAL_RE.test(query),
|
|
733
|
+
isReasoningModel: typeof llmRoute?.model === "string" && REASONING_MODEL_RE.test(llmRoute.model),
|
|
734
|
+
});
|
|
781
735
|
// 纠偏与反思提醒属于任务协议,跟人设无关——挂在 thinking 段
|
|
782
736
|
// 才能在「不使用人设」的纯任务会话里也生效。
|
|
783
737
|
const correction = st?.protocolCorrection;
|
|
@@ -792,4 +746,13 @@ export function apply(ctx, config = {}) {
|
|
|
792
746
|
return [base, route, phase, longSession, anchor, alignment, postTurnReview, toolEvidence, correction, reflectionHint].filter(Boolean).join("\n\n");
|
|
793
747
|
},
|
|
794
748
|
}), "lume.thinking-section()");
|
|
749
|
+
// ── 会话压缩接管(实验特性,默认关闭)──
|
|
750
|
+
// 开启后:宿主提供 ctx.compaction 时用 Lume 的结构化检查点摘要替换 coding 模板;
|
|
751
|
+
// 需配合 profile 的 cordis.patch.yml 禁用 compaction-basic(同名服务不可重复注册)。
|
|
752
|
+
// 默认关闭时完全不注册,避免在未配置的机器上产生无意义的失败日志。
|
|
753
|
+
if (compactionTakeover) {
|
|
754
|
+
// resolveRoute:agent 上取不到路由时用 Lume 自己缓存的主对话路由兜底,
|
|
755
|
+
// 避免摘要静默回退到宿主的 coding 模板。
|
|
756
|
+
void registerLumeCompaction(ctx, ctx.logger, { resolveRoute: () => llmRoute });
|
|
757
|
+
}
|
|
795
758
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lume-dsh-plugin",
|
|
3
3
|
"description": "微光 (Lume) — DSH Desktop 增强插件:Codex 风格自适应任务执行协议 + 人设系统(聊天记录蒸馏具名角色、长期记忆、风格纠偏自动捕获)",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.5",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -51,17 +51,12 @@
|
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
54
|
-
"@deepseek-ai/dsh-client-
|
|
55
|
-
"@deepseek-ai/dsh-
|
|
56
|
-
"@deepseek-ai/dsh-
|
|
57
|
-
"@deepseek-ai/dsh-
|
|
58
|
-
"@deepseek-ai/dsh-
|
|
59
|
-
"@deepseek-ai/dsh-
|
|
60
|
-
"@deepseek-ai/dsh-llm": "^0.0.1-rc.1",
|
|
61
|
-
"@deepseek-ai/dsh-storage-domain": "^0.0.1-rc.1",
|
|
62
|
-
"@deepseek-ai/dsh-system-prompt": "^0.1.1-rc.2",
|
|
63
|
-
"@deepseek-ai/dsh-tools": "^0.0.1-rc.1",
|
|
64
|
-
"@deepseek-ai/dsh-typert-protocol": "^0.1.1-rc.2",
|
|
54
|
+
"@deepseek-ai/dsh-client-ui-primitives": "*",
|
|
55
|
+
"@deepseek-ai/dsh-llm": "*",
|
|
56
|
+
"@deepseek-ai/dsh-storage-domain": "*",
|
|
57
|
+
"@deepseek-ai/dsh-tools": "*",
|
|
58
|
+
"@deepseek-ai/dsh-compaction": "*",
|
|
59
|
+
"@deepseek-ai/dsh-compaction-basic": "*",
|
|
65
60
|
"@deepseek-ai/schemastery": "^3.18.1"
|
|
66
61
|
},
|
|
67
62
|
"scripts": {
|
|
@@ -95,5 +90,31 @@
|
|
|
95
90
|
"assets/personalities.json",
|
|
96
91
|
"assets/personalities/*.txt",
|
|
97
92
|
"assets/personalities/*.jsonl"
|
|
98
|
-
]
|
|
93
|
+
],
|
|
94
|
+
"peerDependenciesMeta": {
|
|
95
|
+
"@deepseek-ai/cordis": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
98
|
+
"@deepseek-ai/dsh-client-ui-primitives": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"@deepseek-ai/dsh-llm": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
104
|
+
"@deepseek-ai/dsh-storage-domain": {
|
|
105
|
+
"optional": true
|
|
106
|
+
},
|
|
107
|
+
"@deepseek-ai/dsh-tools": {
|
|
108
|
+
"optional": true
|
|
109
|
+
},
|
|
110
|
+
"@deepseek-ai/dsh-compaction": {
|
|
111
|
+
"optional": true
|
|
112
|
+
},
|
|
113
|
+
"@deepseek-ai/dsh-compaction-basic": {
|
|
114
|
+
"optional": true
|
|
115
|
+
},
|
|
116
|
+
"@deepseek-ai/schemastery": {
|
|
117
|
+
"optional": true
|
|
118
|
+
}
|
|
119
|
+
}
|
|
99
120
|
}
|