f7a720204a
- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用 - 添加所有子项目的完整源代码 - 保留原始 .git 为 .git.bak 备份
143 lines
4.5 KiB
Rust
143 lines
4.5 KiB
Rust
// TC-AX-01: Multi-feature collaboration test (LOCAL, no LLM).
|
|
//
|
|
// Exercises memory + compression + file cache + tool description all at once.
|
|
|
|
use nomi_agent::compact::micro::{CLEARED_TOOL_RESULT, microcompact};
|
|
use nomi_agent::context::{SystemPromptCache, build_system_prompt};
|
|
use nomi_config::compact::CompactConfig;
|
|
use nomi_config::file_cache::FileCacheConfig;
|
|
use nomi_tools::Tool;
|
|
use nomi_tools::file_cache::FileStateCache;
|
|
use nomi_tools::read::ReadTool;
|
|
use nomi_types::message::{ContentBlock, Message, Role};
|
|
use serde_json::json;
|
|
use std::sync::{Arc, RwLock};
|
|
|
|
#[tokio::test]
|
|
async fn tc_ax_01_multi_feature_collaboration() {
|
|
// ── Step 1: Setup memory directory with MEMORY.md and an entry ──
|
|
let tmp = tempfile::TempDir::new().unwrap();
|
|
let mem_dir = tmp.path().join("memory");
|
|
std::fs::create_dir_all(&mem_dir).unwrap();
|
|
std::fs::write(
|
|
mem_dir.join("MEMORY.md"),
|
|
"- [Preferences](prefs.md) \u{2014} user prefers dark theme\n",
|
|
)
|
|
.unwrap();
|
|
std::fs::write(
|
|
mem_dir.join("prefs.md"),
|
|
"The user prefers dark theme and compact layout.\n",
|
|
)
|
|
.unwrap();
|
|
|
|
// ── Step 2: Build system prompt with memory ──
|
|
let system_prompt = build_system_prompt(
|
|
&mut SystemPromptCache::new(),
|
|
None,
|
|
"/tmp",
|
|
"test-model",
|
|
&[],
|
|
None,
|
|
Some(&mem_dir),
|
|
false, // plan_mode_active = false
|
|
false,
|
|
false, // browser_enabled
|
|
);
|
|
|
|
// Assert: system prompt contains memory content
|
|
assert!(
|
|
system_prompt.contains("auto memory"),
|
|
"system prompt should contain memory system display name"
|
|
);
|
|
assert!(
|
|
system_prompt.contains("prefs.md"),
|
|
"system prompt should reference the memory entry file"
|
|
);
|
|
|
|
// Assert: system prompt contains tool guidance
|
|
assert!(
|
|
system_prompt.contains("# Using your tools"),
|
|
"system prompt should contain tool usage guidance heading"
|
|
);
|
|
|
|
// ── Step 3: ReadTool dedup via FileStateCache ──
|
|
let cache_config = FileCacheConfig {
|
|
max_entries: 100,
|
|
max_size_bytes: 25 * 1024 * 1024,
|
|
enabled: true,
|
|
};
|
|
let cache = Arc::new(RwLock::new(FileStateCache::new(&cache_config)));
|
|
let read_tool = ReadTool::new(Some(Arc::clone(&cache)), None);
|
|
|
|
let test_file = tmp.path().join("test_read.txt");
|
|
std::fs::write(&test_file, "line one\nline two\nline three\n").unwrap();
|
|
|
|
let input = json!({ "file_path": test_file.to_str().unwrap() });
|
|
|
|
// First read: full content
|
|
let r1 = read_tool.execute(input.clone()).await;
|
|
assert!(!r1.is_error, "first read should succeed");
|
|
assert!(
|
|
r1.content.contains("line one"),
|
|
"first read should return file content"
|
|
);
|
|
|
|
// Second read: dedup stub (file unchanged)
|
|
let r2 = read_tool.execute(input).await;
|
|
assert!(!r2.is_error, "second read should succeed");
|
|
assert!(
|
|
r2.content.contains("unchanged since last read"),
|
|
"second read should return dedup stub, got: {}",
|
|
r2.content
|
|
);
|
|
|
|
// ── Step 4: Microcompact clears old tool results ──
|
|
let mut messages = Vec::new();
|
|
for i in 0..8 {
|
|
let id = format!("t{i}");
|
|
messages.push(Message::new(
|
|
Role::Assistant,
|
|
vec![ContentBlock::ToolUse {
|
|
id: id.clone(),
|
|
name: "Read".to_string(),
|
|
input: json!({}),
|
|
extra: None,
|
|
}],
|
|
));
|
|
messages.push(Message::new(
|
|
Role::User,
|
|
vec![ContentBlock::ToolResult {
|
|
tool_use_id: id,
|
|
content: format!("file-content-{i}"),
|
|
is_error: false,
|
|
images: Vec::new(),
|
|
}],
|
|
));
|
|
}
|
|
|
|
let compact_config = CompactConfig {
|
|
micro_keep_recent: 3,
|
|
..CompactConfig::default()
|
|
};
|
|
let result = microcompact(&mut messages, &compact_config);
|
|
|
|
// Assert: microcompact cleared some old tool results
|
|
assert!(
|
|
result.cleared_count > 0,
|
|
"microcompact should clear old tool results, got cleared_count={}",
|
|
result.cleared_count
|
|
);
|
|
|
|
// Verify cleared results contain the placeholder
|
|
let cleared_results: Vec<_> = messages
|
|
.iter()
|
|
.flat_map(|m| &m.content)
|
|
.filter(|b| matches!(b, ContentBlock::ToolResult { content, .. } if content == CLEARED_TOOL_RESULT))
|
|
.collect();
|
|
assert_eq!(
|
|
cleared_results.len(),
|
|
result.cleared_count,
|
|
"number of cleared placeholders should match cleared_count"
|
|
);
|
|
}
|