-
released this
2026-09-08 16:36:30 +08:00 | 0 commits to master since this releaseMetona Ollama Desktop v0.17.2
主题:上下文一致性与持久化正确性 —— 三个正确性缺陷的根治性修复 + 七项行为收敛 + 安全层测试补课。
本次为稳定性专项迭代,不新增功能,全部改动围绕"发给模型的上下文是否正确"与"会话数据是否完整"两条主线。
✨ 正确性修复(P0)
1. 发送路径用户消息重复注入(含图片双份 token)
- 问题:每轮发送时构建的历史消息包含刚追加的当前用户消息,而 Agent Engine 的 INIT 状态会再次注入一次 userContent——用户消息(含图片 base64)以两份进入模型上下文,视觉模型下图片 token 直接翻倍,长对话中持续浪费 token 并可能干扰模型。
- 根治方案:新建纯函数模块
history-builder.ts,将"排除当前轮输入"编码为函数契约(定位末尾当前用户消息并排除其后的所有内容),发送与/retry两条路径共用唯一实现,新增单元测试锁定不变量。 - 连带根治:原实现在 maxCount 截断时因循环内提前 break,长会话实际保留的是最旧的消息(最近的上下文反而被丢弃),已改为从头部裁剪、保留最近消息,且裁剪点不会落在孤立的 tool 消息上。
2. /undo 与 /retry 的删除不落库(重载后"复活")
- 问题:消息保存为纯追加式,
/undo、/retry裁剪掉的消息仍留在 SQLite 中,重启或重新加载会话后全部复活,甚至与新生成的回复交织。 - 根治方案:新增
db:getMessageIds/db:deleteMessagesIPC 通道(sqlite → ipc → preload → types 四层),存储层改为按会话追踪已保存消息 ID + 差量同步:- 首次接触会话时以数据库现有行 ID 为基线(应用重启后同样能 diff 出遗留行);
- 保存时删除被裁剪的消息、只插入新增消息;删除走分块 IN 单事务,保留原有增量插入性能;
- 删除失败时把被删 ID 保留在追踪集中,下次保存自动重试,杜绝永久幽灵行。
3. /compress 手动压缩完全无效
- 问题:手动压缩生成的摘要消息以
role:'system'存储——既不渲染(用户看不见)也不进入后续上下文(历史构建只取 user/assistant),等于空操作。 - 根治方案:
- 摘要改为
role:'user'+ compressed 标记(与自动压缩的既定规范一致),下一轮真正进入模型上下文; - 聊天区新增可折叠"📋 上下文摘要"卡片,摘要可见、可展开查看全文;
- 读取数据库时将旧版遗留的 system 摘要行归一化,保存后自愈;
- compressed 标记随 attachments 持久化,重载后仍正确渲染;
/retry、/undo定位目标时跳过压缩摘要,不会把摘要误当作用户输入重试。
- 摘要改为
🔧 行为收敛修复(P1)
# 修复 说明 1 memory search 默认 limit=8 原实现未传 limit 时返回全部记忆(上限 500 条),模型省略参数会撑爆上下文;现与工具 schema 描述一致 2 工具缓存键稳定序列化 JSON.stringify的 replacer 数组不改变键序,键序不同的相同参数无法命中缓存/去重;新增stableStringify(键排序递归)并应用于缓存键与调用历史3 run_command 超时真正终止进程 原为"伪超时"(不再等待但命令继续后台运行);现超时与用户中止时联动主进程 killToolProcess 终止进程树 4 记忆访问统计写回纳入写入锁 原写回绕过写入锁,与 add/replace/remove 并发时旧缓存可能覆盖掉正在写入的新记忆(丢失记忆) 5 搜索自动抓取单页限幅 自动抓取(最多 8 页)原来不带 max_chars 抓整页全文,现单页限幅 8000 字符,防止内存/上下文尖峰 6 Token 趋势采样去重 采样从 calculateContextStats 内部(一轮内被调用多次)移至 OBSERVING 每轮一次,且记录裁剪后值,线性回归溢出预测不再被重复数据点污染 7 空白 assistant 消息不入库 新迭代与用户中止两条路径上,内容/思考/工具记录全空的消息不再持久化,避免污染会话与轮次统计
🧪 测试与文档(P2)
- 新增
tests/tool-security.test.ts(18 用例):为安全地基 tool-security.ts 补齐测试——系统目录硬红线及其不可豁免穿透、用户敏感目录拦截、工作空间豁免放行、MEMORY.md 全工具禁读写、SOUL/AGENT/USER.md 可读不可写、路径遍历深度拦截、写白名单限制、命令黑名单(POSIX+Windows)、反弹 shell 检测、setAllowedDirs 黑名单穿透过滤。测试平台自适应且不依赖 HOME 位置(兼容以 root 运行的容器 CI)。 - 新增
tests/history-builder.test.ts(11 用例):当前轮排除、_apiContent 附件注入、tool_calls 与 R92 工具结果信封、system 消息永不注入、maxCount 尾部保留与孤立 tool 消息防护。 - 文档与代码事实对齐:帮助/设置面板文案(HTTP 默认 900s、上下文硬上限 300 条、memory 6 个 action、上下文档位 8K–1M 八档)、README 中英文、DEVELOPMENT.md(移除失效文件引用、补充差量同步说明)。
- 工程清理:移除 vendor 库失效 source map 引用(消除构建警告)、移除 .npmrc 弃用的 always-auth 配置。
- 顺带修复:导入 .metona 备份丢失文件/视频附件的问题(导入路径现在携带 attachments)。
✅ 验证
- TypeScript 双 tsconfig 类型检查零错误
- 单元测试 301 通过 / 0 失败(18 个测试文件,合计 302 用例)
- 渲染进程(Vite)+ 主进程(tsc)完整构建通过
📦 升级说明
- 直接覆盖安装即可,无数据库 Schema 迁移(user_version 不变);
- 首次保存会话时会自动以数据库现有行 ID 为基线建立追踪,旧版本遗留的"复活"消息将在下一次保存时按差量清理;
- 旧版本中使用过 /compress 的会话,其中遗留的不可见摘要会在加载后自动归一化为可见的摘要卡片;
- 建议升级后在常用工作流(发送 / 重试 / 撤销 / 压缩 / 记忆 / 联网搜索)各做一轮人工回归。
🙏 完整变更
提交
3fb293c,26 个文件变更(+789 / −201),新增 3 个文件(history-builder.ts 及两个测试文件)。Downloads