Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-3E63DD?style=flat-square" alt="license"></a>
<a href="https://github.com/slow-stack/mneme/actions"><img src="https://img.shields.io/github/actions/workflow/status/slow-stack/mneme/ci.yml?style=flat-square&label=CI" alt="CI"></a>
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-22%2B-3E63DD?style=flat-square&logo=nodedotjs&logoColor=white" alt="node"></a>
<a href="https://github.com/slow-stack/mneme"><img src="https://img.shields.io/badge/tests-1370%20passed-3E63DD?style=flat-square" alt="tests"></a>
<a href="https://github.com/slow-stack/mneme"><img src="https://img.shields.io/badge/tests-1370%20passed-3E63DD?style=flat-square" alt="tests"></a>
<a href="https://github.com/slow-stack/mneme"><img src="https://img.shields.io/badge/tests-1389%20passed-3E63DD?style=flat-square" alt="tests"></a>
<a href="https://github.com/slow-stack/mneme"><img src="https://img.shields.io/badge/tests-1389%20passed-3E63DD?style=flat-square" alt="tests"></a>
<a href="https://codecov.io/gh/slow-stack/mneme"><img src="https://img.shields.io/codecov/c/github/slow-stack/mneme/main?style=flat-square" alt="coverage"></a>
<a href="https://github.com/awesome-dsh-plugin/awesome-dsh-plugin"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="Awesome"></a>
</p>
Expand Down Expand Up @@ -183,8 +183,8 @@ dsh web

```bash
cd dsh-mneme && npm install
npm test # 1342 个测试
npm test # 1342 个测试
npm test # 1389 个测试
npm test # 1389 个测试
npm run stress # 三轴线压测
npm run sync # src → lib 同步
```
Expand Down Expand Up @@ -366,8 +366,8 @@ The plugin ships a zero-dependency stdio MCP server (standalone npm package **`m

```bash
cd dsh-mneme && npm install
npm test # 1342 tests
npm test # 1342 tests
npm test # 1389 tests
npm test # 1389 tests
npm run stress # three-axis stress test
npm run sync # src → lib sync
```
Expand Down
2 changes: 2 additions & 0 deletions dsh-mneme/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@

## 🆕 新增

- **蒸馏思考强度设置项(issue #315)**:蒸馏(会话总结提炼)LLM 新增 `summarizeReasoningEffort`(`off`/`low`/`medium`/`high`/`none`,默认 `none` = 不发送字段、服务商默认生效,行为与此前一致)。思考型模型蒸馏时推理会烧光输出预算、总结为空或截断(#9 同款失败面,此前仅巩固/睡眠/实体抽取三链路有档位控制),配 `off`/`low` 可封顶推理。档位被模型拒收时自动去掉字段重试一次(与巩固/睡眠同一降级策略,`withEffortFallback` 共享、拒收判别式 `EFFORT_REJECT_RE` 提为单一来源);面板「功能开关 → 自动总结」下新增档位下拉(opt-in 语义与实体抽取 `entityExtractionReasoning` 对齐,settings 白名单注册)。新增回归 5 条(`test/summarize-reasoning-effort.test.js`)。

- **压缩边缘双落点(issue #249 N3)**:上下文即将被宿主压缩前抢救「正在做什么」,新增
opt-in 键 `continuityRescueEnabled`(注入父开关 `autoInject` 的子项,默认关;`lightMode`
强制关)。**必须是双落点**:①落一条连续性提案到新表 `continuity_proposals`(脱离对话
Expand Down
12 changes: 6 additions & 6 deletions dsh-mneme/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
[![npm version](https://img.shields.io/npm/v/@modusensus/dsh-mneme?color=blue&label=npm)](https://www.npmjs.com/package/@modusensus/dsh-mneme)
[![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![Awesome](https://awesome-dsh-plugin.com/badge.svg)](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin)
[![tests](https://img.shields.io/badge/tests-1370%20passed-success)](https://github.com/slow-stack/mneme)
[![tests](https://img.shields.io/badge/tests-1370%20passed-success)](https://github.com/slow-stack/mneme)
[![tests](https://img.shields.io/badge/tests-1389%20passed-success)](https://github.com/slow-stack/mneme)
[![tests](https://img.shields.io/badge/tests-1389%20passed-success)](https://github.com/slow-stack/mneme)
[![CI](https://img.shields.io/github/actions/workflow/status/slow-stack/mneme/ci.yml)](https://github.com/slow-stack/mneme/actions)
[![node](https://img.shields.io/badge/node-22%2B-blue)](https://nodejs.org)
[![npm downloads](https://img.shields.io/npm/d18m/@modusensus/dsh-mneme.svg?color=blue&label=downloads)](https://www.npmjs.com/package/@modusensus/dsh-mneme)
Expand Down Expand Up @@ -582,8 +582,8 @@ src/
├── api.js # HTTP 路由(Web 面板数据通道,含 /conflicts 冲突队列)
└── index.js # 插件接线
lib/ # src 的同步分发产物(npm run sync;发布前由 root prepack 的 check-sync.js 校验一致性;唯一手写例外 lib/client.js——Web 面板 bundle,sync 不覆盖)
test/ # 1342 个 node:test 测试(审计与三轴线压测不变量;src↔lib 一致性由 scripts/check-sync.js 发布闸门校验)
test/ # 1342 个 node:test 测试(审计与三轴线压测不变量;src↔lib 一致性由 scripts/check-sync.js 发布闸门校验)
test/ # 1389 个 node:test 测试(审计与三轴线压测不变量;src↔lib 一致性由 scripts/check-sync.js 发布闸门校验)
test/ # 1389 个 node:test 测试(审计与三轴线压测不变量;src↔lib 一致性由 scripts/check-sync.js 发布闸门校验)
scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压测 · sync-lib.js 同步 · check-sync.js 发布闸门 · benchmark-recall.js / benchmark-embed.js / benchmark-rerank.js 基准 · sync-test-badge.mjs 测试徽章 · build-runtime-manifest.mjs 运行时清单
```

Expand All @@ -592,8 +592,8 @@ scripts/ # e2e-dsh.js 端到端演示 · stress-dsh.js 三轴线压
```bash
cd dsh-mneme
npm install # 安装 peer 依赖(以 devDependencies 形式,用于本地测试)
npm test # 运行 1342 个测试
npm test # 运行 1342 个测试
npm test # 运行 1389 个测试
npm test # 运行 1389 个测试
npm run stress # 三轴线压测:长会话检索 / 冲突仲裁 / 多 Agent 并发(离线 mock LLM)
npm run sync # 把 src/ 同步到 lib/(发布时由 prepack 钩子自动执行)
```
Expand Down
35 changes: 35 additions & 0 deletions dsh-mneme/lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,13 @@ window.__ModuleLoader__.load({
"memory.features.entityExtractionReasoning.low": "低",
"memory.features.entityExtractionReasoning.medium": "中",
"memory.features.entityExtractionReasoning.high": "高",
"memory.features.summarizeReasoningEffort": "蒸馏思考强度",
"memory.features.summarizeReasoningEffort.off": "关闭思考",
"memory.features.summarizeReasoningEffort.none": "跟随默认",
"memory.features.summarizeReasoningEffort.low": "低",
"memory.features.summarizeReasoningEffort.medium": "中",
"memory.features.summarizeReasoningEffort.high": "高",
"memory.features.summarizeReasoningEffort.hint": "思考型模型建议选低档或关闭思考,避免推理烧光输出预算导致总结失败;改后重启 DSH 生效",
"memory.features.entityExtractionModelHint": "Provider/模型留空 = 跟随主对话模型;思考强度 none = 服务商默认",
"memory.features.codingRetrospect": "编码记忆蒸馏",
"memory.features.codingRetrospect.hint": "用完整转录(含工具调用与报错)提炼踩坑、约束与被否决方案",
Expand Down Expand Up @@ -787,6 +794,13 @@ window.__ModuleLoader__.load({
"memory.features.entityExtractionReasoning.low": "Low",
"memory.features.entityExtractionReasoning.medium": "Medium",
"memory.features.entityExtractionReasoning.high": "High",
"memory.features.summarizeReasoningEffort": "Distill reasoning effort",
"memory.features.summarizeReasoningEffort.off": "No reasoning",
"memory.features.summarizeReasoningEffort.none": "Follow default",
"memory.features.summarizeReasoningEffort.low": "Low",
"memory.features.summarizeReasoningEffort.medium": "Medium",
"memory.features.summarizeReasoningEffort.high": "High",
"memory.features.summarizeReasoningEffort.hint": "Prefer low or No reasoning for thinking models so reasoning cannot drain the output budget; takes effect after a DSH restart",
"memory.features.entityExtractionModelHint": "Provider / model empty = follow the main conversation model; reasoning none = provider default",
"memory.features.codingRetrospect": "Coding retrospection",
"memory.features.codingRetrospect.hint": "Distill pitfalls, constraints and rejected solutions from full transcripts (tools and errors included)",
Expand Down Expand Up @@ -1950,6 +1964,9 @@ window.__ModuleLoader__.load({
const EMBED_PROVIDERS = ["openai", "local", "ollama"];
// 实体抽取思考强度(issue #109):与后端 FEATURE_FLAG_ENUMS 枚举对齐。
const ENTITY_REASONING = ["none", "low", "medium", "high"];
// 蒸馏思考强度(issue #315):比 entity 多一个 off(显式关思考,思考型模型
// 蒸馏防推理烧预算)。后端枚举含 off,面板必须能选到,否则操作者用不上。
const SUMMARIZE_REASONING = ["off", "none", "low", "medium", "high"];

function FeatureRow({ name, hint, on, disabled, onToggle, sub }) {
return h("div", { className: "mneme-featrow", style: sub ? { paddingLeft: 18, opacity: 0.86 } : undefined },
Expand Down Expand Up @@ -2235,6 +2252,23 @@ window.__ModuleLoader__.load({
h("div", { className: "mneme-featsubhint" }, t("memory.features.entityExtractionModelHint"))
);

// 蒸馏思考强度(issue #315):autoSummarize 开着才展开,档位与实体抽取
// 同款枚举下拉、即时提交。蒸馏没有独立 provider/model 路由键(跟随会话
// 头或 config 文件的 summarizeProvider/summarizeModel),不上连通性测试。
const summarizeSub = eff.autoSummarize && h("div", { className: "mneme-featsub" },
h("div", { className: "mneme-featnum" },
h("span", { className: "mneme-featnumlabel" }, t("memory.features.summarizeReasoningEffort")),
h("select", {
className: "mneme-select",
value: eff.summarizeReasoningEffort || "none",
disabled: busy,
onChange: (e) => put({ summarizeReasoningEffort: e.target.value })
},
SUMMARIZE_REASONING.map((r) => h("option", { key: r, value: r }, t(`memory.features.summarizeReasoningEffort.${r}`))))
),
h("div", { className: "mneme-featsubhint" }, t("memory.features.summarizeReasoningEffort.hint"))
);

if (error && !state) return h("section", { className: "mneme-set-card" },
h("div", { className: "mneme-set-title" }, t("memory.features.title")),
h("div", { className: "mneme-set-hint" }, error));
Expand All @@ -2252,6 +2286,7 @@ window.__ModuleLoader__.load({
FEATURE_GROUPS.map((g) => h(react.Fragment, { key: g.key },
h("div", { className: "mneme-featgroup" }, t(`memory.features.${g.key}`)),
g.items.map(flagRow),
g.key === "group.core" && h(react.Fragment, null, summarizeSub),
g.key === "group.enhance" && h(react.Fragment, null, embedSub, entitySub),
g.key === "group.dream" && h(react.Fragment, null, dreamSub, sleepSub)
)),
Expand Down
17 changes: 17 additions & 0 deletions dsh-mneme/lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,23 @@ export const Config = z.object({
z.const("high"),
z.const("none")
]).description("同 dreamReasoningEffort:sleep 各阶段 LLM 的推理档位,未配置 = 自动取模型支持的最低档;显式 'none' = 不发送字段、用服务商自带默认。"),
// Pass-through reasoning effort for the distill (summarize) LLM call
// (issue #315). Mirrors entityExtractionReasoning rather than dream: the
// default 'none' omits the field entirely (provider default), so current
// behavior is unchanged until the user opts in — no auto-lowest resolution
// here, distill failures are retried at the window level anyway. off/low/
// medium/high are forwarded verbatim; a provider that rejects the effort
// retries once without it (withEffortFallback), so opting in is safe to
// experiment with. The failure being addressed is the #9 shape on the
// distill path: a thinking model drains the output budget on reasoning and
// the summary comes back empty/truncated.
summarizeReasoningEffort: z.union([
z.const("off"),
z.const("low"),
z.const("medium"),
z.const("high"),
z.const("none")
]).default("none").description("蒸馏(会话总结提炼)LLM 的推理档位:默认 'none' = 不发送字段、用服务商自带默认;off/low/medium/high 原样传递,被模型拒收时自动去掉字段重试一次(与巩固/睡眠同款降级,#315)。思考型模型建议 off/low,避免推理烧光输出预算。"),
// Issue #257:sleep 冲突/模式两阶段的输出预算(原硬编码 2048)。实测默认档
// 每对裁决约 90 token、24 对 2097——2048 恰好压在边界(53 次运行 48 败);
// full 档六分支实测约 290 token/对、24 对 6967,2048 必然截断。默认 8192
Expand Down
10 changes: 8 additions & 2 deletions dsh-mneme/lib/dream.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ async function runAuditedLlm(ctx, service, config, spec, body) {
* accepted → reasoning capped; rejected → provider default (old behavior),
* logged so the rejection is observable.
*/
// Issue #315:effort 拒收判别式的单一来源。summarize 的流失败以 aborted 结果
// 返回,需在折叠成 undefined 前用同一甄别(各处手写会漂移)。
export const EFFORT_REJECT_RE = /reasoning[\s_]*effort|UNSUPPORTED_REASONING_EFFORT/i;
async function withEffortFallback(ctx, effort, attempt, fallback, getStreamError) {
if (!effort || effort === "none") return attempt();
try {
Expand All @@ -351,17 +354,20 @@ async function withEffortFallback(ctx, effort, attempt, fallback, getStreamError
// on the chunk's failure reason here or the retry below is dead code
// for the stream path.
const reason = String(getStreamError?.() ?? "");
if (/reasoning[\s_]*effort|UNSUPPORTED_REASONING_EFFORT/i.test(reason)) {
if (EFFORT_REJECT_RE.test(reason)) {
ctx.logger?.warn?.(`dsh-mneme dream: reasoningEffort "${effort}" rejected via stream (${reason}); retrying without it`);
return fallback();
}
}
return result;
} catch (error) {
// dispose/取消中止直接放行,绝不能被误判成 effort 拒收而触发 fallback
//(取消后重打一次不带 effort 的调用是浪费,且可能掩盖真实的取消意图)。
if (error?.name === "AbortError") throw error;
const message = String(error?.message ?? error);
// matches both "reasoning effort" (natural language) and the bare
// "UNSUPPORTED_REASONING_EFFORT" error code (underscore).
if (!/reasoning[\s_]*effort/i.test(message)) throw error;
if (!EFFORT_REJECT_RE.test(message)) throw error;
ctx.logger?.warn?.(`dsh-mneme dream: reasoningEffort "${effort}" rejected (${message}); retrying without it`);
return fallback();
}
Expand Down
3 changes: 3 additions & 0 deletions dsh-mneme/lib/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ const FEATURE_FLAG_ENUMS = {
recallFusion: ["blend", "rrf", "minmax"],
// 实体抽取思考强度(issue #109):与 dreamReasoningEffort 枚举对齐。
entityExtractionReasoning: ["low", "medium", "high", "none"],
// 蒸馏思考强度(issue #315):与 entityExtractionReasoning 枚举对齐,
// 多一个 off(显式关思考,思考型模型蒸馏防推理烧预算)。
summarizeReasoningEffort: ["off", "low", "medium", "high", "none"],
// Issue #127:落库前去重档位(off 默认,等同现状)。
summarizeDedupeMode: ["off", "title", "vector"],
// Issue #126:sleep 冲突阶段的动作集(conflict 默认 = 现状;full = 六分支)。
Expand Down
Loading
Loading