Files
freedak f7a720204a Update: 将子项目从 submodule 转为完整内容
- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用
- 添加所有子项目的完整源代码
- 保留原始 .git 为 .git.bak 备份
2026-07-04 19:20:46 +08:00

198 lines
6.2 KiB
Rust

// Acceptance tests for the memory system end-to-end.
//
// These tests verify that the memory system's file I/O, index management,
// and prompt building work together correctly. No LLM API calls are needed.
use nomi_agent::context::{SystemPromptCache, build_system_prompt};
use nomi_memory::index::{append_index_entry, remove_index_entry};
use nomi_memory::paths::ENTRYPOINT_NAME;
use nomi_memory::store::{delete_memory, write_memory};
use nomi_memory::types::{MemoryEntry, MemoryType};
/// TC-A1-01: Memory injection into system prompt.
///
/// Verifies that when a memory directory exists with an index file and a
/// memory entry, `build_system_prompt()` produces output containing both
/// the compact behavioral instructions and the MEMORY.md index content.
#[test]
fn memory_injection_into_system_prompt() {
let tmp = tempfile::TempDir::new().unwrap();
let mem_dir = tmp.path().join("memory");
std::fs::create_dir_all(&mem_dir).unwrap();
// Write MEMORY.md index with one entry
let index_path = mem_dir.join(ENTRYPOINT_NAME);
std::fs::write(
&index_path,
"# Memory Index\n\n- [User role](user_role.md) \u{2014} senior Rust engineer\n",
)
.unwrap();
// Write a corresponding memory entry file
std::fs::write(
mem_dir.join("user_role.md"),
"---\nname: user_role\ndescription: senior Rust engineer\ntype: user\n---\n\nThe user is a senior Rust engineer.\n",
)
.unwrap();
let prompt = build_system_prompt(
&mut SystemPromptCache::new(),
None,
"/tmp",
"test-model",
&[],
None,
Some(&mem_dir),
false,
false,
false, // browser_enabled
);
// Behavioral instructions must be present
assert!(
prompt.contains("auto memory"),
"system prompt should contain the memory display name"
);
assert!(
prompt.contains("Memory types:"),
"system prompt should contain the compact memory type summary"
);
// MEMORY.md content must be injected
assert!(
prompt.contains("user_role.md"),
"system prompt should contain the MEMORY.md index filename reference"
);
assert!(
prompt.contains("senior Rust engineer"),
"system prompt should contain the MEMORY.md index summary"
);
}
/// TC-A1-02: Memory full lifecycle (create, index, verify, delete, verify gone).
///
/// Exercises the complete lifecycle of a memory entry through the public API:
/// 1. write_memory() -> create the file
/// 2. append_index_entry() -> add to MEMORY.md
/// 3. build_system_prompt() -> verify the content appears
/// 4. delete_memory() -> remove the file
/// 5. remove_index_entry() -> clean the index
/// 6. build_system_prompt() -> verify the content is gone
#[test]
fn memory_full_lifecycle() {
let tmp = tempfile::TempDir::new().unwrap();
let mem_dir = tmp.path().join("memory");
std::fs::create_dir_all(&mem_dir).unwrap();
let index_path = mem_dir.join(ENTRYPOINT_NAME);
// -- Phase 1: Create memory entry via the store API -----------------------
let entry = MemoryEntry::build(
"project status",
"current sprint goals",
MemoryType::Project,
"We are migrating the auth service to the new provider.",
);
let entry_path = write_memory(&mem_dir, &entry).unwrap();
assert!(entry_path.exists(), "memory file should be created on disk");
let entry_filename = entry_path.file_name().unwrap().to_str().unwrap().to_owned();
// -- Phase 2: Add the entry to the MEMORY.md index ------------------------
append_index_entry(
&index_path,
"Project status",
&entry_filename,
"current sprint goals",
)
.unwrap();
let index_content = std::fs::read_to_string(&index_path).unwrap();
assert!(
index_content.contains(&entry_filename),
"MEMORY.md should reference the new entry file"
);
// -- Phase 3: Verify system prompt includes the memory content ------------
let prompt_with_memory = build_system_prompt(
&mut SystemPromptCache::new(),
None,
"/tmp",
"test-model",
&[],
None,
Some(&mem_dir),
false,
false,
false, // browser_enabled
);
assert!(
prompt_with_memory.contains("auto memory"),
"prompt should contain behavioral instructions"
);
assert!(
prompt_with_memory.contains("Memory types:"),
"prompt should contain compact memory type summary"
);
assert!(
prompt_with_memory.contains(&entry_filename),
"prompt should contain the memory entry filename from the index"
);
assert!(
prompt_with_memory.contains("current sprint goals"),
"prompt should contain the index summary"
);
// -- Phase 4: Delete the memory file --------------------------------------
delete_memory(&entry_path).unwrap();
assert!(
!entry_path.exists(),
"memory file should be removed from disk"
);
// -- Phase 5: Remove the entry from the MEMORY.md index -------------------
remove_index_entry(&index_path, &entry_filename).unwrap();
let index_after = std::fs::read_to_string(&index_path).unwrap();
assert!(
!index_after.contains(&entry_filename),
"MEMORY.md should no longer reference the deleted entry"
);
// -- Phase 6: Verify the content is gone from the system prompt -----------
let prompt_after_delete = build_system_prompt(
&mut SystemPromptCache::new(),
None,
"/tmp",
"test-model",
&[],
None,
Some(&mem_dir),
false,
false,
false, // browser_enabled
);
assert!(
!prompt_after_delete.contains(&entry_filename),
"prompt should no longer contain the deleted entry filename"
);
assert!(
!prompt_after_delete.contains("current sprint goals"),
"prompt should no longer contain the deleted entry summary"
);
// With everything removed, the index is empty — the prompt should show the empty state
assert!(
prompt_after_delete.contains("currently empty"),
"prompt should show empty memory state after all entries are removed"
);
}