修复: namespace 占位符发 LLM 前未展开 + key 含斜杠丢原文

This commit is contained in:
lxy
2026-08-01 10:42:09 +08:00
parent bd9031d35d
commit 468950616b
3 changed files with 55 additions and 6 deletions
+23 -4
View File
@@ -157,11 +157,18 @@ impl NamespaceStore {
}
}
/// 简单的基于长度的哈希(唯一性由 content 长度 + 前 16 字符保证)
/// 用于构建引用路径中的 key 段,不需要密码学强度
/// 内容 → 引用 key 段(确定性,不含 `/` 等会破坏 `parse_namespace_key` 的字符)。
///
/// 历史 bug:旧实现用 `"{len}_{前16字符}"`,前 16 字符原样进 key;内容前缀含 `/`(目录列表、
/// 带路径的 grep 结果、文件头是路径)时,`namespace://tool/{key}` 被 `parse_namespace_key`
/// 的 `split('/').nth(1)` 从首个 `/` 截断 → read/read_only 拿回 None → 原文彻底丢失。
/// 现改用 SipHash u64 → 16 位 hex:确定性 + 极低碰撞 + 不含特殊字符。
fn simple_hash(content: &str) -> String {
let prefix: String = content.chars().take(16).collect();
format!("{}_{}", content.len(), prefix)
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
content.hash(&mut hasher);
format!("{:016x}", hasher.finish())
}
#[cfg(test)]
@@ -226,6 +233,18 @@ mod tests {
assert_eq!(r1, r2);
}
#[test]
fn store_content_with_slash_in_prefix_reads_back() {
// 回归:旧 simple_hash 把内容前 16 字符原样进 key,前缀含 '/' 时(目录列表/带路径 grep
// 结果/文件头是路径)namespace://tool/{key} 被 parse_namespace_key 的 split('/') 截断
// → read None,原文丢失。hex hash 修复后 store→read 正确取回。
let mut ns = NamespaceStore::new(100_000);
let content = "foo/bar/baz/qux\nline2\nline3";
let path = ns.store("list_directory", content);
assert!(is_namespace_ref(&path));
assert_eq!(ns.read(&path).map(str::to_owned), Some(content.to_string()));
}
#[test]
fn eviction_oldest_removed_when_over_limit() {
let mut ns = NamespaceStore::new(100); // 极小容量