• v0.17.2
    CI / verify (push) Successful in 1m53s
    Stable

    thzxx released this 2026-09-08 16:36:30 +08:00 | 0 commits to master since this release

    Metona 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:deleteMessages IPC 通道(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