Skip to content
Open
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
3 changes: 3 additions & 0 deletions dsh-mneme/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## [Unreleased]

- **`dream_runs` 第一次有了保留期:`dreamRunsTrimDays`(opt-in 默认 0)裁掉窗口外轮次的重载列,行与骨架一个字节都不动(#557)**:这张表是四个 `*RetentionDays` 都不覆盖、也没有任何 `DELETE` 路径的唯一一张——单行 `input` 快照体量随记忆数涨、轮数随天数涨,两个因子**相乘超线性**(报告库占约 43% 的页),再叠加热快照 `VACUUM INTO` 是整库副本,它同时放大库与备份两处开销。issue 的建议 1(加保留期键 + 启动期清理)方向对,但按 11-04 的评论对齐口径落地:维护者 2026-09-23 拍板 3 是「**裁列同意、删行不同意**」,而 `dream_runs` 的每一行能回放一次巩固是 `distill_runs` 不复用它的理由——所以这里**不删行、不判「最近 N 轮」**(那三处读最新行的消费者 `lastDreamRunAt` / `lastDreamBaseline` / `getLatestPolicyEpoch` 读的全是骨架列,不受裁剪影响,自然也不必为它们保尾)。裁的是三列重载:`input`(记忆库快照,可由库重建)、`decisions`(原始 LLM 决策)、`outcome`(action 映射)——issue 评论实测列文本 13.26 MB 里 50.1% + 30.5% + 17.8%;`snapshot_hash` / `status` / `provider` / `receipt` / `policy_epoch` / `store_count` 等骨架列与行本身永远保留,窗口外轮次的离线回放降级为**骨架级**(与 `reclaim` 清 input、`dreamInputSummaryEnabled` 的瘦身同一条口径,`docs/CONFIGURATION.md` 写明三处互不冲突)。**`organize` 行整体豁免**:它的 `input` 是 apply 的重放载荷、`outcome` 挂着 `dry_run_id` / `applied_at` 链,裁了会让 apply 静默空转并锁死报告——谓词与 `clearDreamRunInputs` 同一条边界。**opt-in 默认 0 = 不裁**:升级后行为逐字节不变,键的形态对齐 `recallRetentionDays` 一族(顶层扁平键、只从配置文件改、`settings.js` 白名单同族现状一样不进——族里还没人开「进面板」这个头,要开得同时补 `api.js` 的 NESTED 表与 `client.js` 的面板行)。启动期执行(与其余四张表同策略:读装配后的 cfg、失败只 warn 不挡启动),**真裁到了才出一行 info**——常态一个字都不出,别把启动日志刷成心跳。`dreamRunsTrimStats` 与 `trimDreamRunPayloads` 共用同一谓词,报告数字与执行数字同源。回归测试 7 条(窗口外裁三列且骨架列逐列不变 / 行永不删 / organize 整体豁免 / 重跑 changes 为 0 / stats 与执行同口径 / 空表与无命中不抛 / 配置键默认 0 与边界 + 文档面列出该键 + 接线锁「0 不裁、读 cfg、失败只 warn」)。变异自证 4 例(删 organize 豁免 → 2 红;`> 0` 改 `>= 0` → 1 红;默认改 90 → 1 红;裁剪 SQL 漏掉 `outcome` → 3 红),恢复后全绿。

## [0.14.0-beta.3] - 2026-11-12
- **品牌视觉换新:README 头图与插件列表图标**。三处 README(根、`dsh-mneme/`、`mcp/`)顶部改用 `images/mneme-banner-hero.webp`(1672×941,282 KiB)——原图 2.1 MiB 的 PNG 会让 `images/` 目录体积翻倍。根目录用相对路径,两个子目录用 raw 绝对地址:npm 详情页不解析相对图片路径,`../images/...` 在 npmjs.com 上必然裂图。
- **插件列表图标从手绘 SVG 换成位图**:`package.json` 的 `icon` 改为 `assets/icon.png`(256×256 RGBA、圆角透明、120 KiB,仍在宿主 `iconOf()` 的 256 KiB 上限内);`assets/icon.svg` 删除。列表图标不再要求与客户端内联 mark(`MNEME_MARK_D`)同形,`test/client.test.js` 的图标用例改验 PNG 魔数、IHDR 边长、位深与 RGBA 通道——宿主对坏文件是静默回落成通用插画,不报错。

Expand Down
1 change: 1 addition & 0 deletions dsh-mneme/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ dsh web
| `sleepReasoningEffort` | 未配置=最低档 | sleep 各阶段 LLM 推理档位(同 dreamReasoningEffort 语义,v0.7.26) |
| `recallRecordDefault` | `true` | recall_runs 记录默认开(显式传 `recordRecall:false` 的调用方不受影响);注入同样落账(`mode='inject'`,随本开关,#217) |
| `recallRetentionDays` | `90` | recall_runs 滚动清理保留天数 |
| `dreamRunsTrimDays` | `0` | dream_runs 重载列(input/decisions/outcome)的启动期裁剪窗口(天);0 = 不裁。裁列不删行(#557),organize 行豁免,窗口外回放降级为骨架级 |
| `hotMemoryRounds` | `5` | 会话级短期热记忆轮次(v0.5.0):最近 N 轮对话滚动注入,从会话事件日志无状态重建、不落库 |
| `hotMemoryMaxTokens` | `2000` | 热记忆 token 预算(v0.5.0,200-32000),超出滚动截断 |
| `selectiveInjectEnabled` | `true` | 选择性注入(v0.5.0):query 向量可用时注入候选按主题相似度重排,替代固定规则序 |
Expand Down
1 change: 1 addition & 0 deletions dsh-mneme/docs/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@
| `evalPersistTestResults` | `false` | 检索评测快照落 `recall_evals` | 生产检索恒只进 `recall_runs`,与此键无关 |
| `recallRecordDefault` | `true` | `recall_runs` 记录默认开 | 显式传 `false` 的调用方不受影响 |
| `recallRetentionDays` | `90` | `recall_runs` 滚动清理保留天数 | — |
| `dreamRunsTrimDays` | `0` | `dream_runs` 重载列(input / decisions / outcome)的启动期裁剪窗口(天) | opt-in,`0` = 不裁(#557:该表单行体量随记忆数、轮数随天数,相乘超线性,是四个保留期键都不覆盖的无界大户)。**裁列不删行**(拍板 3):骨架列与 receipt 永远保留,窗口外轮次的离线回放降级为骨架级;`organize` 行整体豁免(input 是 apply 的重放载荷)。与 `dreamInputSummaryEnabled`(写入期瘦身)、`dsh-mneme reclaim`(手动回收)互不冲突:三处都只是把对应列置空 |
| `trustEpistemicWeighting` | `false` | 来源可信度(observation/subjective/inferred)参与排序与标注 | opt-in;关时 epistemic_status 只是惰性数据 |

### 重排层
Expand Down
10 changes: 10 additions & 0 deletions dsh-mneme/lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,16 @@ export const Config = z.object({
recallRecordDefault: z.boolean().default(true),
// recall_runs 滚动清理保留天数。
recallRetentionDays: z.natural().min(1).max(3650).default(90),
// dream_runs 重载列(input 快照 / decisions / outcome)的启动期裁剪窗口(天),
// opt-in 默认 0 = 不裁(现状逐字节不变;#557:这张表是四个 *RetentionDays 都不
// 覆盖的无界增长大户,单行体量随记忆数涨、轮数随天数涨,相乘超线性)。拍板 3:
// 裁列同意、删行不同意——行与骨架列永远保留,回放能力对窗口外的轮次降级为骨架
// 级(与 reclaim 清 input、dreamInputSummaryEnabled 的瘦身同一条口径);organize
// 行整体豁免(input 是 apply 的重放载荷)。顶层扁平键、只从配置文件改,与
// recallRetentionDays 同族(进面板要同时补 api.js 的 NESTED 表与 client.js 的
// 面板行,族里还没人开这个头)。窗口别配得比「最近几轮」还短:/dream-status 的
// 最近 5 轮里被裁掉的老轮,decisions.demotion 会退化成 null(骨架与时间戳不受影响)。
dreamRunsTrimDays: z.natural().min(0).max(3650).default(0),

// --- tool exposure: 慢模型/轻量模型的工具往返节流(v0.8.5)----------------
// 跨会话记忆已由 inject.js 每轮自动注入系统提示词,memory_search 只用于
Expand Down
15 changes: 15 additions & 0 deletions dsh-mneme/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,21 @@ export const apply = (ctx, config) => {
ctx.logger?.warn?.(`[dsh-mneme] recall_runs retention purge failed: ${String(err)}`);
}

// #557:dream_runs 重载列(input / decisions / outcome)的启动期裁剪。opt-in 默认
// 0 = 不裁(零行为变化);开窗后与上面四处同策略——读装配后的 cfg、失败只 warn
// 不挡启动。裁的是列不是行(拍板 3),organize 行豁免(store 层谓词,与 reclaim
// 的 clearDreamRunInputs 同一条边界)。真裁到了才出一行 info:常态(库还小 /
// 没开窗)一个字都不出,别把启动日志刷成心跳。
try {
const dreamRunsTrimDays = Number.isInteger(cfg.dreamRunsTrimDays) ? cfg.dreamRunsTrimDays : 0;
if (dreamRunsTrimDays > 0) {
const trimmed = store.trimDreamRunPayloads(new Date(Date.now() - dreamRunsTrimDays * 86400000).toISOString());
if (trimmed > 0) ctx.logger?.info?.(`[dsh-mneme] dream_runs payload trim: ${trimmed} run(s) beyond the ${dreamRunsTrimDays}d window (columns cleared, rows kept)`);
}
} catch (err) {
ctx.logger?.warn?.(`[dsh-mneme] dream_runs payload trim failed: ${String(err)}`);
}

// 记忆语言(memory.language):本实例逐层传入 inject / summarize / dream /
// sleep / mirror,多实例(如 agent preset 内挂载)互不影响。
const mirror = createMirror(memoryDir, langOf(cfg));
Expand Down
34 changes: 34 additions & 0 deletions dsh-mneme/lib/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -3871,6 +3871,38 @@ export function createStore(path) {
).run(before).changes;
}

// #557 的裁列面:input 之外的大头是 decisions / outcome 两列 JSON(issue 评论区
// 实测 13.26 MB 列文本里 50.1% + 30.5%)。拍板 3 的口径是「裁列同意、删行不同意」
// ——行与骨架列(status / provider / receipt / policy_epoch / store_count…)永远
// 保留,回放能力对窗口外的轮次降级为骨架级(与 reclaim 清 input、#625 的瘦身同
// 一条口径)。organize 行整体豁免:input 是 apply 的重放载荷、outcome 挂着
// dry_run_id / applied_at 链,裁了会让 apply 静默空转(clearDreamRunInputs 的同一
// 条边界)。读侧已逐个核对:lastDreamRunAt / lastDreamBaseline / getLatestPolicyEpoch
// 读的都是骨架列,/dream-status 的 decisions.demotion 是可选链(裁掉的老轮退化成
// null);reclaim 的 A 项刻意不碰 decisions/outcome——那是「随手跑的无损回收」的
// 边界,这里是显式配置键(dreamRunsTrimDays,opt-in 默认 0 = 关)驱动的启动期裁剪。
function dreamRunsTrimStats(before) {
const row = db.prepare(
`SELECT count(*) AS c,
COALESCE(SUM(LENGTH(input)), 0) + COALESCE(SUM(LENGTH(decisions)), 0)
+ COALESCE(SUM(LENGTH(outcome)), 0) AS b
FROM dream_runs
WHERE created_at < ? AND run_type != 'organize'
AND (input IS NOT NULL OR decisions IS NOT NULL OR outcome IS NOT NULL)`
).get(before);
return { runs: row.c, bytes: row.b };
}

/** 裁掉窗口外 run 的三列重载(organize 豁免)。返回实际改动的行数;重跑幂等。 */
function trimDreamRunPayloads(before) {
return db.prepare(
`UPDATE dream_runs
SET input = NULL, decisions = NULL, outcome = NULL
WHERE created_at < ? AND run_type != 'organize'
AND (input IS NOT NULL OR decisions IS NOT NULL OR outcome IS NOT NULL)`
).run(before).changes;
}

/**
* 归档行仍带的向量统计(#275 B 项)。检索 SQL 恒带 `archived = 0`,所以这部分
* 向量按定义不可达,清掉不改变任何检索结果。
Expand Down Expand Up @@ -5986,6 +6018,8 @@ export function createStore(path) {
// 存储生命周期(#275 第一批):无损回收的统计、清理与体积口径。
dreamRunInputStats,
clearDreamRunInputs,
dreamRunsTrimStats,
trimDreamRunPayloads,
archivedEmbeddingStats,
clearArchivedEmbeddings,
storageStats,
Expand Down
10 changes: 10 additions & 0 deletions dsh-mneme/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,16 @@ export const Config = z.object({
recallRecordDefault: z.boolean().default(true),
// recall_runs 滚动清理保留天数。
recallRetentionDays: z.natural().min(1).max(3650).default(90),
// dream_runs 重载列(input 快照 / decisions / outcome)的启动期裁剪窗口(天),
// opt-in 默认 0 = 不裁(现状逐字节不变;#557:这张表是四个 *RetentionDays 都不
// 覆盖的无界增长大户,单行体量随记忆数涨、轮数随天数涨,相乘超线性)。拍板 3:
// 裁列同意、删行不同意——行与骨架列永远保留,回放能力对窗口外的轮次降级为骨架
// 级(与 reclaim 清 input、dreamInputSummaryEnabled 的瘦身同一条口径);organize
// 行整体豁免(input 是 apply 的重放载荷)。顶层扁平键、只从配置文件改,与
// recallRetentionDays 同族(进面板要同时补 api.js 的 NESTED 表与 client.js 的
// 面板行,族里还没人开这个头)。窗口别配得比「最近几轮」还短:/dream-status 的
// 最近 5 轮里被裁掉的老轮,decisions.demotion 会退化成 null(骨架与时间戳不受影响)。
dreamRunsTrimDays: z.natural().min(0).max(3650).default(0),

// --- tool exposure: 慢模型/轻量模型的工具往返节流(v0.8.5)----------------
// 跨会话记忆已由 inject.js 每轮自动注入系统提示词,memory_search 只用于
Expand Down
15 changes: 15 additions & 0 deletions dsh-mneme/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,21 @@ export const apply = (ctx, config) => {
ctx.logger?.warn?.(`[dsh-mneme] recall_runs retention purge failed: ${String(err)}`);
}

// #557:dream_runs 重载列(input / decisions / outcome)的启动期裁剪。opt-in 默认
// 0 = 不裁(零行为变化);开窗后与上面四处同策略——读装配后的 cfg、失败只 warn
// 不挡启动。裁的是列不是行(拍板 3),organize 行豁免(store 层谓词,与 reclaim
// 的 clearDreamRunInputs 同一条边界)。真裁到了才出一行 info:常态(库还小 /
// 没开窗)一个字都不出,别把启动日志刷成心跳。
try {
const dreamRunsTrimDays = Number.isInteger(cfg.dreamRunsTrimDays) ? cfg.dreamRunsTrimDays : 0;
if (dreamRunsTrimDays > 0) {
const trimmed = store.trimDreamRunPayloads(new Date(Date.now() - dreamRunsTrimDays * 86400000).toISOString());
if (trimmed > 0) ctx.logger?.info?.(`[dsh-mneme] dream_runs payload trim: ${trimmed} run(s) beyond the ${dreamRunsTrimDays}d window (columns cleared, rows kept)`);
}
} catch (err) {
ctx.logger?.warn?.(`[dsh-mneme] dream_runs payload trim failed: ${String(err)}`);
}

// 记忆语言(memory.language):本实例逐层传入 inject / summarize / dream /
// sleep / mirror,多实例(如 agent preset 内挂载)互不影响。
const mirror = createMirror(memoryDir, langOf(cfg));
Expand Down
34 changes: 34 additions & 0 deletions dsh-mneme/src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -3871,6 +3871,38 @@ export function createStore(path) {
).run(before).changes;
}

// #557 的裁列面:input 之外的大头是 decisions / outcome 两列 JSON(issue 评论区
// 实测 13.26 MB 列文本里 50.1% + 30.5%)。拍板 3 的口径是「裁列同意、删行不同意」
// ——行与骨架列(status / provider / receipt / policy_epoch / store_count…)永远
// 保留,回放能力对窗口外的轮次降级为骨架级(与 reclaim 清 input、#625 的瘦身同
// 一条口径)。organize 行整体豁免:input 是 apply 的重放载荷、outcome 挂着
// dry_run_id / applied_at 链,裁了会让 apply 静默空转(clearDreamRunInputs 的同一
// 条边界)。读侧已逐个核对:lastDreamRunAt / lastDreamBaseline / getLatestPolicyEpoch
// 读的都是骨架列,/dream-status 的 decisions.demotion 是可选链(裁掉的老轮退化成
// null);reclaim 的 A 项刻意不碰 decisions/outcome——那是「随手跑的无损回收」的
// 边界,这里是显式配置键(dreamRunsTrimDays,opt-in 默认 0 = 关)驱动的启动期裁剪。
function dreamRunsTrimStats(before) {
const row = db.prepare(
`SELECT count(*) AS c,
COALESCE(SUM(LENGTH(input)), 0) + COALESCE(SUM(LENGTH(decisions)), 0)
+ COALESCE(SUM(LENGTH(outcome)), 0) AS b
FROM dream_runs
WHERE created_at < ? AND run_type != 'organize'
AND (input IS NOT NULL OR decisions IS NOT NULL OR outcome IS NOT NULL)`
).get(before);
return { runs: row.c, bytes: row.b };
}

/** 裁掉窗口外 run 的三列重载(organize 豁免)。返回实际改动的行数;重跑幂等。 */
function trimDreamRunPayloads(before) {
return db.prepare(
`UPDATE dream_runs
SET input = NULL, decisions = NULL, outcome = NULL
WHERE created_at < ? AND run_type != 'organize'
AND (input IS NOT NULL OR decisions IS NOT NULL OR outcome IS NOT NULL)`
).run(before).changes;
}

/**
* 归档行仍带的向量统计(#275 B 项)。检索 SQL 恒带 `archived = 0`,所以这部分
* 向量按定义不可达,清掉不改变任何检索结果。
Expand Down Expand Up @@ -5986,6 +6018,8 @@ export function createStore(path) {
// 存储生命周期(#275 第一批):无损回收的统计、清理与体积口径。
dreamRunInputStats,
clearDreamRunInputs,
dreamRunsTrimStats,
trimDreamRunPayloads,
archivedEmbeddingStats,
clearArchivedEmbeddings,
storageStats,
Expand Down
Loading
Loading