Files
zclaw_openfang/crates/zclaw-growth/tests/memory_embedding_test.rs
iven 79e7cd3446
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
test(growth,runtime,skills): 深度验证测试 Phase 1-2 — 20 个新测试
- MockLlmDriver 基础设施 (zclaw-runtime/src/test_util.rs)
- 经验闭环 E-01~06: 累积/溢出/反序列化/跨行业/并发/阈值
- Embedding 管道 EM-01~08: 路由/降级/维度不匹配/空查询/CJK/LLM Fallback/热更新
- Skill 执行 SK-01~03: 工具传递/纯 Prompt/锁竞争
2026-04-21 19:00:29 +08:00

144 lines
5.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Memory embedding tests (EM-07 ~ EM-08)
//!
//! Validates memory retrieval with embedding enhancement and configuration hot-update.
use std::sync::Arc;
use async_trait::async_trait;
use zclaw_growth::{
EmbeddingClient, MemoryEntry, MemoryRetriever, MemoryType, SqliteStorage, VikingAdapter,
};
use zclaw_types::AgentId;
/// Mock embedding client that returns deterministic 128-dim vectors.
struct MockEmbeddingClient {
dim: usize,
}
impl MockEmbeddingClient {
fn new() -> Self {
Self { dim: 128 }
}
}
#[async_trait::async_trait]
impl EmbeddingClient for MockEmbeddingClient {
async fn embed(&self, text: &str) -> Result<Vec<f32>, String> {
let mut vec = vec![0.0f32; self.dim];
for (i, b) in text.as_bytes().iter().enumerate() {
vec[i % self.dim] += (*b as f32) / 255.0;
}
let norm: f32 = vec.iter().map(|v| v * v).sum::<f32>().sqrt().max(1e-8);
for v in vec.iter_mut() {
*v /= norm;
}
Ok(vec)
}
fn is_available(&self) -> bool {
true
}
}
/// EM-07: Memory retrieval with embedding enhancement.
#[tokio::test]
async fn em07_memory_retrieval_embedding_enhanced() {
let storage = Arc::new(SqliteStorage::in_memory().await);
let adapter = Arc::new(VikingAdapter::new(storage));
let agent_id = AgentId::new();
// Store 20 mixed Chinese/English memories
let entries = vec![
("pref-theme", MemoryType::Preference, "用户偏好深色模式"),
("pref-language", MemoryType::Preference, "用户使用中文沟通"),
("know-rust", MemoryType::Knowledge, "Rust async programming with tokio"),
("know-python", MemoryType::Knowledge, "Python data science with pandas"),
("exp-report", MemoryType::Experience, "月度报表生成经验使用Excel宏自动化"),
("know-react", MemoryType::Knowledge, "React hooks patterns"),
("pref-editor", MemoryType::Preference, "偏好 VS Code 编辑器"),
("exp-schedule", MemoryType::Experience, "排班冲突解决方案:协商调换"),
("know-sql", MemoryType::Knowledge, "SQL query optimization techniques"),
("exp-deploy", MemoryType::Experience, "部署失败经验:端口冲突检测"),
("know-docker", MemoryType::Knowledge, "Docker container networking"),
("pref-font", MemoryType::Preference, "字体大小偏好 14px"),
("know-tokio", MemoryType::Knowledge, "Tokio runtime configuration"),
("exp-review", MemoryType::Experience, "代码审查经验:关注错误处理"),
("know-git", MemoryType::Knowledge, "Git rebase vs merge strategies"),
("exp-perf", MemoryType::Experience, "性能优化经验:数据库索引"),
("pref-timezone", MemoryType::Preference, "时区 UTC+8"),
("know-linux", MemoryType::Knowledge, "Linux system administration basics"),
("exp-test", MemoryType::Experience, "测试经验TDD方法论实践"),
("know-api", MemoryType::Knowledge, "RESTful API design principles"),
];
for (key, mtype, content) in &entries {
let entry = MemoryEntry::new(
&agent_id.to_string(),
*mtype,
key,
content.to_string(),
);
adapter.store(&entry).await.unwrap();
}
// Create retriever with embedding
let retriever = MemoryRetriever::new(adapter);
retriever.set_embedding_client(Arc::new(MockEmbeddingClient::new()));
// Retrieve memories about user preferences
let result = retriever
.retrieve(&agent_id, "我之前说过什么偏好?")
.await
.unwrap();
let total =
result.knowledge.len() + result.preferences.len() + result.experience.len();
assert!(
total > 0,
"embedding-enhanced retrieval should find memories"
);
assert!(
result.preferences.len() > 0,
"should find preference memories"
);
}
/// EM-08: Embedding configuration hot update — no panic, no disruption.
#[tokio::test]
async fn em08_embedding_hot_update() {
let storage = Arc::new(SqliteStorage::in_memory().await);
let adapter = Arc::new(VikingAdapter::new(storage));
let agent_id = AgentId::new();
// Store a memory
let entry = MemoryEntry::new(
&agent_id.to_string(),
MemoryType::Knowledge,
"rust-async",
"Tokio runtime uses work-stealing scheduler".to_string(),
);
adapter.store(&entry).await.unwrap();
// Start without embedding
let retriever = MemoryRetriever::new(adapter);
// Retrieve without embedding — should not panic
let _result_before = retriever
.retrieve(&agent_id, "async runtime")
.await
.unwrap();
// Hot-update with embedding — should not disrupt ongoing operations
retriever.set_embedding_client(Arc::new(MockEmbeddingClient::new()));
// Retrieve with embedding — should not panic
let _result_after = retriever
.retrieve(&agent_id, "async runtime")
.await
.unwrap();
// Key assertion: hot-update does not panic or disrupt
}