f7a720204a
- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用 - 添加所有子项目的完整源代码 - 保留原始 .git 为 .git.bak 备份
198 lines
6.2 KiB
Rust
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"
|
|
);
|
|
}
|