|
4 | 4 |
|
5 | 5 | --- |
6 | 6 |
|
7 | | -## [Unreleased] |
| 7 | +## [0.3.6] - 2026-05-27 |
| 8 | + |
| 9 | +### ✨ 新功能 |
| 10 | + |
| 11 | +- **Recall 上下文预算控制** ([#71](https://github.com/Tencent/TencentDB-Agent-Memory/pull/71) / [#70](https://github.com/Tencent/TencentDB-Agent-Memory/issues/70)):新增 `recall.maxCharsPerMemory` 与 `recall.maxTotalRecallChars` 两项配置,默认 `0` 不改变现有行为;设置为正整数后,会在 L1 召回完成、注入 `<relevant-memories>` 之前按分数顺序裁剪超长条目并丢弃溢出部分,避免长会话因记忆膨胀挤占上下文。已在 README、README_CN 与 `openclaw.plugin.json` 同步说明。 |
| 12 | +- **L1 / L2 / L3 提示词按用户输入语言自适应** ([#38](https://github.com/Tencent/TencentDB-Agent-Memory/issues/38)):`l1-extraction`、`l1-dedup`、`scene-extraction`、`persona-generation` 四个 prompt 中所有自由文本字段(`scene_name`、记忆 `content`、scene `.md` 标题/正文、`persona.md` 各章节)现在跟随用户消息的主导语言书写;JSON 字段名、枚举值、ISO 时间戳、`persona.md` 等结构化文件名继续保持英文作为稳定契约。无需配置 `locale`,任意语言(en / fr / ja / es / …)均可直接使用。 |
| 13 | +- **Embedding `sendDimensions` 可选关闭**:`OpenAIEmbeddingService` 默认仍会在请求体携带 `dimensions` 字段(兼容 OpenAI `text-embedding-3-*` Matryoshka 截断);新增 `embedding.sendDimensions` 配置项,设置为 `false` 时省略该字段,可对接 BGE-M3 等不支持自定义维度的固定维度模型(原会被服务端 HTTP 400 拒绝 `does not support matryoshka representation`)。 |
| 14 | +- **Gateway 可选 Bearer 鉴权 + CORS 白名单**:新增 `server.apiKey` / `TDAI_GATEWAY_API_KEY` 配置项,设置后所有非 `/health` 路由需携带 `Authorization: Bearer <key>`(`crypto.timingSafeEqual` 防时序攻击);新增 `server.corsOrigins` / `TDAI_CORS_ORIGINS` 配置项,显式指定允许的 CORS 来源列表(空列表 = 不发送 CORS 头,`"*"` = 保留旧版宽松行为)。启动时打印安全态势摘要,非回环地址 + 无 apiKey 时输出 WARN。两项均默认关闭,现有部署无需改动。Hermes Python 客户端同步支持 `MEMORY_TENCENTDB_GATEWAY_API_KEY` 环境变量自动附加 Bearer 头。 |
| 15 | +- **Offload `collect` 模式**:新增 `offload.mode: "collect"` 配置,仅执行数据采集(L0 捕获 + 向量写入)而不触发 L3 压缩,适用于纯数据积累阶段或调试场景。 |
8 | 16 |
|
9 | 17 | ### 🐛 修复 |
10 | 18 |
|
11 | | -- **Hermes Docker 镜像 `config.yaml` 缺少 `api_key` 字段**:`Dockerfile.hermes` 的 CMD 脚本将 API Key 写入了 `.env` 的 `OPENAI_API_KEY`,但未写入 `config.yaml` 的 `model.api_key`,导致 `provider: custom` 时 Hermes 无法找到认证凭据(报 401 Authentication Fails)。现修复为在 `config.yaml` 的 `model` 段同步写入 `api_key: "${MODEL_API_KEY}"`。 |
| 19 | +#### 数据安全 / 数据隔离 |
| 20 | +- **L2 LLM 提取失败导致 `scene_blocks/` 被清空 / 半写入** ([#88](https://github.com/Tencent/TencentDB-Agent-Memory/issues/88)):Phase 1 已对 `scene_blocks/` 做完整快照,但 LLM 抛错时 `catch` 直接 `return`,沙箱里的部分写入 / 删除不会回滚,后续 recall 因此看不到场景导航,降级为碎片召回。新增 `BackupManager.findLatestBackup` + `restoreLatestDirectory`,在 LLM 失败时自动从最新备份恢复;采用 fail-soft 设计:无备份时不动目标目录,恢复过程自身的错误也不会替换原始 LLM 错误。 |
| 21 | +- **Cleaner 安全加固**:`computeCutoffMsByLocalDay` 拒绝无效 cutoff(未来时间 / 距今不足 24h);SQLite 与 TCVDB 在 `expired/total > 80%` 时阻止删除;`runOnce` 增加最小保留护栏(L0:50 / L1:20)并产出 `cleaner_summary` JSON 审计日志;新增 `__tests__/cleaner/verify-cleaner-safety.ts` E2E 校验。 |
| 22 | +- **场景文件名含空格导致 Persona Scene Navigation 引用失效**:LLM 在 L2 偶发用 `Daily Rhythm in Shanghai.md` 这类含空格的名字创建 scene block,导致 `persona.md` 中 `### Path: scene_blocks/<name>.md` 引用无法被下游 `\S+\.md` 风格解析器(health-checker 等)识别,soak 后健康检查必报 `Scene Navigation 存在但无场景引用`。修复:(1) `scene-extraction` prompt 增加"📛 文件命名规范(强制)"段,禁止空格 / 括号 / 引号等标点;(2) 新增 `core/scene/filename-normalizer.ts`,在 `SceneExtractor.extract` Phase 5b(cleanup 后、`syncSceneIndex` 前)自动归一化文件名(空格 → `-`、剥离危险标点、冲突时追加 `-2` 后缀),下游 PersonaGenerator / recall / profile-sync 自动使用干净名,无需改动。 |
| 23 | + |
| 24 | +#### OpenClaw 宿主兼容 |
| 25 | +- **`api.runtime.state` 在新版 OpenClaw 上为 `undefined` 导致注册时崩溃** ([#78](https://github.com/Tencent/TencentDB-Agent-Memory/issues/78) / [#85](https://github.com/Tencent/TencentDB-Agent-Memory/pull/85) / [#79](https://github.com/Tencent/TencentDB-Agent-Memory/pull/79)):为两处调用点加可选链 + fallback,优先调用宿主 `runtimeState.resolveStateDir()`,缺失时退到 `OPENCLAW_STATE_DIR` 环境变量,再退到 `~/.openclaw`。同时修复 cli-metadata 注册模式下 `runtime` 为空对象 `{}` 仍会触发 `TypeError` 的问题(在该模式下提前 return,只调用 `registerCli`)。 |
| 26 | +- **`contextEngine` slot ID 与插件名不一致**:`registerContextEngine` 的 ID 从 `openclaw-context-offload` 改为 `memory-tencentdb`,避免 `openclaw doctor --fix` 把 slot 重置;`setup-offload.sh` 中的 `CONTEXT_ENGINE_ID` 同步更新。 |
| 27 | +- **L1.5 settle 永不返回导致 L2 卡死**:在 L2 poll 中为 L1.5 settle 增加 60s 超时,当未配置 Context Engine slot 导致 `assemble` 永不被调用时,自动 force-settle 解锁 L2。 |
| 28 | +- **Standalone 文本任务仍暴露工具导致 DeepSeek 等后端 L1 抽取不稳定** ([#58](https://github.com/Tencent/TencentDB-Agent-Memory/issues/58) / [#59](https://github.com/Tencent/TencentDB-Agent-Memory/pull/59)):`enableTools=false` 时彻底不传工具列表(此前即便只读子集也会鼓励 OpenAI 兼容后端尝试 tool calling,DeepSeek 上尤其明显)。 |
| 29 | +- **L2 cold-start skip 被错误地更新 `l2LastRunTime`**:导致首次 skip 后必须等满 `l2MaxInterval` 才会真正运行 L2;现在仅在确实跑过的情况下更新时间戳。 |
| 30 | + |
| 31 | +#### Offload(Context Engine)稳定性 |
| 32 | +- **`sanitizeText` 误删 emoji / CJK Extension B / Math Bold 等非 BMP 字符** ([#30](https://github.com/Tencent/TencentDB-Agent-Memory/issues/30) / [#31](https://github.com/Tencent/TencentDB-Agent-Memory/pull/31)):`UNSAFE_CHAR_RE` 含 `[\uD800-\uDFFF]` 但缺 `u` flag,JS 按 UTF-16 code unit 处理时会把每个非 BMP 码点的两个 surrogate 各自 strip 掉。加上 `u` flag 后只匹配孤立(畸形)surrogate,emoji / 扩展 CJK / 数学加粗等正常恢复;新增 vitest 套件覆盖保留与剥离两类 case。 |
| 33 | +- **Emergency 截断在 `MIN_KEEP` 拒绝下死锁**:`EMERGENCY_MIN_MESSAGES_TO_KEEP` 由 4 降到 2;新增 `_emergencyTruncateOversized`,当 head/tail 删除均被阻塞时就地截断超大消息(保留 `tool_use` 块结构),最后兜底强制删除并配对清理 `toolResult`,在 LLM 可见的内容里加截断告示。 |
| 34 | +- **多轮 aggressive compression 累计耗时**:由 6 轮 `O(N × rounds)` 全量 tiktoken 改为单趟 `O(N × 1)` 直接计算到目标阈值的精确切点。615 条消息从 84s 降到 ~14s;tool 配对、user 消息保护、MMD 保留、stall 检测等安全机制全部保留。 |
| 35 | +- **FP-HEAD-DELETE 在多轮 FAST-SKIP 后误删新消息**:移除该路径,改用 `FP-BOUNDARY-DELETE`(基于上一轮 aggressive 边界的 O(1) 头部删除,index + fingerprint 双重验证、tool-pair 安全)+ `BOUNDARY-INCR-SKIP`(增量估算低于阈值时跳过 tiktoken)。重放场景下 `assemble` 38s → 122ms(310×)。 |
| 36 | +- **首次 assemble 慢**:为 `TAIL-ACCUMULATE` 增加 fast-token-estimate(基于字符,~51× 快于 tiktoken)前置短路,无边界且 fast estimate 明显高于阈值时跳过全量 tiktoken;同时为 `TAIL-ACCUMULATE` 增加向后 tool-pair 校正、user 消息保护、最少保留 10 条等安全检查。首次 assemble 29s → ~1.4s。 |
| 37 | +- **Token 计算精度**:`details` 字段加入 `INTERNAL_KEYS`(框架在送 LLM 前 strip 掉,不应计入 token);新增 `_stripLargeFields()` 移除非内容大字段;就地截断后调用 `invalidateTokenCache(msg)` 修正 WeakMap 缓存陈旧问题;`bestTokens < 600` 时跳过截断防反向膨胀;stub 文本简化为纯英文避免触发模型内容过滤;`l3TiktokenEncoding` 默认从 `o200k_base` 改为 `cl100k_base`(匹配 DeepSeek / GLM / MiniMax 分词器)。 |
| 38 | +- **Offload 日志降级**:`AGGRESSIVE` / `EMERGENCY` 等多数日志降到 debug,仅当超过 10s 时才输出 `SLOW` warn;Opik tracer 初始化、`after_tool_call` 无 session 等"正常 fallback"场景日志同步降级,减少 `plugins list` 噪音。 |
| 39 | + |
| 40 | +#### Hermes / Docker 部署 |
| 41 | +- **`Dockerfile.hermes` 生成的 `config.yaml` 缺 `api_key`** ([#77](https://github.com/Tencent/TencentDB-Agent-Memory/issues/77) / [#81](https://github.com/Tencent/TencentDB-Agent-Memory/pull/81)):`provider: custom` 模式下 Hermes 从 `config.yaml.model.api_key` 读密钥,而原 CMD 脚本仅写入 `.env` 的 `OPENAI_API_KEY`,造成容器内首条对话即报 401。修复为同步写入 `model.api_key: "${MODEL_API_KEY}"`。 |
| 42 | +- **安装脚本多处问题** ([#18](https://github.com/Tencent/TencentDB-Agent-Memory/issues/18) / [#19](https://github.com/Tencent/TencentDB-Agent-Memory/issues/19) / [#20](https://github.com/Tencent/TencentDB-Agent-Memory/issues/20) / [#54](https://github.com/Tencent/TencentDB-Agent-Memory/pull/54) / [#55](https://github.com/Tencent/TencentDB-Agent-Memory/pull/55)): |
| 43 | + - 支持 `HERMES_AGENT_DIR` 环境变量覆盖,适配 FHS 布局(把 hermes-agent 装在 `/usr/local/lib/hermes-agent` 等)。 |
| 44 | + - root 用户执行时不再 `su - root` 无限递归。 |
| 45 | + - `MEMORY_TENCENTDB_GATEWAY_CMD` 在 systemd 环境下用 `command -v node` 解析的绝对路径,`npx tsx` 改为 `node --import tsx/esm`,避免 nvm PATH 不可见时找不到 node。 |
| 46 | + |
| 47 | +### ✨ 改进 |
| 48 | + |
| 49 | +- **L1.5 settle 60s 超时保护**(详见上)。 |
| 50 | +- **OpenAI-style standalone runner** 在 `enableTools=false` 时不再传任何工具(详见上)。 |
| 51 | +- **`l3TiktokenEncoding` 默认改为 `cl100k_base`**,匹配主流国产/开源模型分词器。 |
| 52 | +- **Docker 文档**:补充 `cd docker/opensource` 前置步骤;新增 question/consultation issue 模板。 |
| 53 | + |
| 54 | +### 🧪 测试 / 内部 |
| 55 | + |
| 56 | +- 新增 `src/utils/backup.test.ts`:`findLatestBackup` 4 个用例 + `restoreLatestDirectory` 5 个用例,真 fs 沙箱。 |
| 57 | +- 新增 `src/core/scene/scene-extractor.restore.integration.test.ts`:用真临时目录 + 真 BackupManager 验证 LLM 失败时 `scene_blocks/` 被恢复(含 step 日志,沙箱保留供人工 inspect)。 |
| 58 | +- 新增 `src/utils/openclaw-state-dir.test.ts` + `index.test.ts` cli-metadata 模式安全性用例。 |
| 59 | +- 新增 `__tests__/cleaner/verify-cleaner-safety.ts` E2E(SQLite + live VDB)。 |
| 60 | +- 新增 `src/offload/fast-token-estimate.ts` + `benchmark-token-estimate.ts` 基线脚本。 |
| 61 | + |
| 62 | +### ⚠️ 配置项变化(向后兼容) |
| 63 | + |
| 64 | +| Key | 默认值 | 说明 | |
| 65 | +|---|---|---| |
| 66 | +| `recall.maxCharsPerMemory` | `0` | `0`/未设置 = 不裁剪 | |
| 67 | +| `recall.maxTotalRecallChars` | `0` | `0`/未设置 = 不裁剪 | |
| 68 | +| `embedding.sendDimensions` | `true` | `false` 时不在请求体携带 `dimensions`,适配 BGE-M3 等 | |
| 69 | +| `l3TiktokenEncoding` | `cl100k_base`(原 `o200k_base`) | 仅在显式依赖 `o200k_base` 时需手动覆盖回去 | |
12 | 70 |
|
13 | 71 | --- |
14 | 72 |
|
|
0 commit comments