Update: 将子项目从 submodule 转为完整内容
- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用 - 添加所有子项目的完整源代码 - 保留原始 .git 为 .git.bak 备份
This commit is contained in:
@@ -0,0 +1,375 @@
|
||||
//! Integration tests for system prompt tool usage guidance (TC-4.3-01 through TC-4.3-08).
|
||||
//!
|
||||
//! Black-box tests verifying the "# Using your tools" section is correctly
|
||||
//! assembled into the system prompt with proper content and ordering.
|
||||
|
||||
use std::fs;
|
||||
|
||||
use nomi_agent::context::{SystemPromptCache, build_system_prompt};
|
||||
use nomi_skills::types::{ExecutionContext, LoadedFrom, SkillMetadata, SkillSource};
|
||||
|
||||
fn make_skill(name: &str, description: &str) -> SkillMetadata {
|
||||
SkillMetadata {
|
||||
name: name.to_string(),
|
||||
display_name: None,
|
||||
description: description.to_string(),
|
||||
has_user_specified_description: false,
|
||||
allowed_tools: vec![],
|
||||
argument_hint: None,
|
||||
argument_names: vec![],
|
||||
when_to_use: None,
|
||||
version: None,
|
||||
model: None,
|
||||
disable_model_invocation: false,
|
||||
user_invocable: true,
|
||||
execution_context: ExecutionContext::Inline,
|
||||
agent: None,
|
||||
effort: None,
|
||||
shell: None,
|
||||
paths: vec![],
|
||||
hooks_raw: None,
|
||||
source: SkillSource::User,
|
||||
loaded_from: LoadedFrom::Skills,
|
||||
content: String::new(),
|
||||
content_length: 0,
|
||||
skill_root: None,
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TC-4.3-01: Tool guidance section exists
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn tc_4_3_01_tool_guidance_section_exists() {
|
||||
let result = build_system_prompt(
|
||||
&mut SystemPromptCache::new(),
|
||||
None,
|
||||
"/tmp",
|
||||
"test-model",
|
||||
&[],
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
false, // browser_enabled
|
||||
);
|
||||
assert!(
|
||||
result.contains("# Using your tools"),
|
||||
"system prompt should contain the tool guidance section heading"
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TC-4.3-02: Bash prohibition list with dedicated tool alternatives
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn tc_4_3_02_bash_prohibition_list() {
|
||||
let result = build_system_prompt(
|
||||
&mut SystemPromptCache::new(),
|
||||
None,
|
||||
"/tmp",
|
||||
"test-model",
|
||||
&[],
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
false, // browser_enabled
|
||||
);
|
||||
|
||||
// Glob replaces find/ls
|
||||
assert!(
|
||||
result.contains("Glob") && result.contains("find"),
|
||||
"should map Glob as replacement for find"
|
||||
);
|
||||
// Grep replaces grep/rg
|
||||
assert!(
|
||||
result.contains("Grep") && result.contains("grep"),
|
||||
"should map Grep as replacement for grep"
|
||||
);
|
||||
// Read replaces cat/head/tail
|
||||
assert!(
|
||||
result.contains("Read") && result.contains("cat"),
|
||||
"should map Read as replacement for cat"
|
||||
);
|
||||
// Edit replaces sed/awk
|
||||
assert!(
|
||||
result.contains("Edit") && result.contains("sed"),
|
||||
"should map Edit as replacement for sed"
|
||||
);
|
||||
// Write replaces echo/heredoc
|
||||
assert!(
|
||||
result.contains("Write") && result.contains("echo"),
|
||||
"should map Write as replacement for echo"
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TC-4.3-03: Parallel call guidance
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn tc_4_3_03_parallel_call_guidance() {
|
||||
let result = build_system_prompt(
|
||||
&mut SystemPromptCache::new(),
|
||||
None,
|
||||
"/tmp",
|
||||
"test-model",
|
||||
&[],
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
false, // browser_enabled
|
||||
);
|
||||
assert!(
|
||||
result.contains("parallel"),
|
||||
"should contain parallel call guidance"
|
||||
);
|
||||
assert!(
|
||||
result.contains("sequentially"),
|
||||
"should explain when to run sequentially (dependencies)"
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TC-4.3-04: Edit-over-Write and Read-before-Edit rules
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn tc_4_3_04_edit_write_read_rules() {
|
||||
let result = build_system_prompt(
|
||||
&mut SystemPromptCache::new(),
|
||||
None,
|
||||
"/tmp",
|
||||
"test-model",
|
||||
&[],
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
false, // browser_enabled
|
||||
);
|
||||
assert!(
|
||||
result.contains("Prefer Edit over Write"),
|
||||
"should contain Edit-over-Write preference"
|
||||
);
|
||||
assert!(
|
||||
result.contains("Read a file before editing"),
|
||||
"should contain Read-before-Edit rule"
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TC-4.3-05: Section order — guidance after intro, before custom prompt
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn tc_4_3_05_order_after_intro_before_custom() {
|
||||
let result = build_system_prompt(
|
||||
&mut SystemPromptCache::new(),
|
||||
Some("CUSTOM_PROMPT_MARKER"),
|
||||
"/tmp",
|
||||
"test-model",
|
||||
&[],
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
false, // browser_enabled
|
||||
);
|
||||
|
||||
let intro_pos = result
|
||||
.find("Working directory")
|
||||
.expect("intro should contain 'Working directory'");
|
||||
let guidance_pos = result
|
||||
.find("# Using your tools")
|
||||
.expect("tool guidance section should exist");
|
||||
let custom_pos = result
|
||||
.find("CUSTOM_PROMPT_MARKER")
|
||||
.expect("custom prompt should exist");
|
||||
|
||||
assert!(
|
||||
guidance_pos > intro_pos,
|
||||
"tool guidance should appear after the base intro"
|
||||
);
|
||||
assert!(
|
||||
guidance_pos < custom_pos,
|
||||
"tool guidance should appear before custom prompt"
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TC-4.3-06: Section order — guidance before skills and memory
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn tc_4_3_06_order_before_skills() {
|
||||
let skills = vec![make_skill("order-test-skill", "Order test")];
|
||||
let result = build_system_prompt(
|
||||
&mut SystemPromptCache::new(),
|
||||
None,
|
||||
"/tmp",
|
||||
"test-model",
|
||||
&skills,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
false, // browser_enabled
|
||||
);
|
||||
|
||||
let guidance_pos = result
|
||||
.find("# Using your tools")
|
||||
.expect("tool guidance should exist");
|
||||
let skills_pos = result
|
||||
.find("order-test-skill")
|
||||
.expect("skill should be listed");
|
||||
|
||||
assert!(
|
||||
guidance_pos < skills_pos,
|
||||
"tool guidance should appear before skills listing"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tc_4_3_06_order_before_memory() {
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let mem_dir = tmp.path().join("memory");
|
||||
fs::create_dir_all(&mem_dir).unwrap();
|
||||
fs::write(
|
||||
mem_dir.join("MEMORY.md"),
|
||||
"- [Note](note.md) \u{2014} some note\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let result = build_system_prompt(
|
||||
&mut SystemPromptCache::new(),
|
||||
None,
|
||||
"/tmp",
|
||||
"test-model",
|
||||
&[],
|
||||
None,
|
||||
Some(&mem_dir),
|
||||
false,
|
||||
false,
|
||||
false, // browser_enabled
|
||||
);
|
||||
|
||||
let guidance_pos = result
|
||||
.find("# Using your tools")
|
||||
.expect("tool guidance should exist");
|
||||
let memory_pos = result
|
||||
.find("auto memory")
|
||||
.expect("memory section should exist");
|
||||
|
||||
assert!(
|
||||
guidance_pos < memory_pos,
|
||||
"tool guidance should appear before memory section"
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TC-4.3-07: All sections coexist with correct ordering
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn tc_4_3_07_all_sections_coexist() {
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let cwd = tmp.path();
|
||||
|
||||
// Create AGENTS.md
|
||||
fs::write(cwd.join("AGENTS.md"), "PROJECT_RULES_COEXIST").unwrap();
|
||||
|
||||
// Create memory
|
||||
let mem_dir = tmp.path().join("memory");
|
||||
fs::create_dir_all(&mem_dir).unwrap();
|
||||
fs::write(
|
||||
mem_dir.join("MEMORY.md"),
|
||||
"- [Item](item.md) \u{2014} coexist test\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let skills = vec![make_skill("coexist-skill", "Coexist test")];
|
||||
|
||||
let result = build_system_prompt(
|
||||
&mut SystemPromptCache::new(),
|
||||
Some("CUSTOM_COEXIST"),
|
||||
&cwd.to_string_lossy(),
|
||||
"test-model",
|
||||
&skills,
|
||||
None,
|
||||
Some(&mem_dir),
|
||||
true, // plan mode active
|
||||
false,
|
||||
false, // browser_enabled
|
||||
);
|
||||
|
||||
// All sections should exist
|
||||
assert!(result.contains("Working directory"), "intro should exist");
|
||||
assert!(
|
||||
result.contains("# Using your tools"),
|
||||
"tool guidance should exist"
|
||||
);
|
||||
assert!(
|
||||
result.contains("CUSTOM_COEXIST"),
|
||||
"custom prompt should exist"
|
||||
);
|
||||
assert!(
|
||||
result.contains("PROJECT_RULES_COEXIST"),
|
||||
"AGENTS.md should exist"
|
||||
);
|
||||
assert!(
|
||||
result.contains("auto memory"),
|
||||
"memory section should exist"
|
||||
);
|
||||
assert!(
|
||||
result.contains("coexist-skill"),
|
||||
"skills listing should exist"
|
||||
);
|
||||
|
||||
// Verify ordering: intro < guidance < custom < agents.md < memory < skills
|
||||
let intro_pos = result.find("Working directory").unwrap();
|
||||
let guidance_pos = result.find("# Using your tools").unwrap();
|
||||
let custom_pos = result.find("CUSTOM_COEXIST").unwrap();
|
||||
let agents_pos = result.find("PROJECT_RULES_COEXIST").unwrap();
|
||||
let memory_pos = result.find("auto memory").unwrap();
|
||||
let skills_pos = result.find("coexist-skill").unwrap();
|
||||
|
||||
assert!(guidance_pos > intro_pos, "guidance after intro");
|
||||
assert!(custom_pos > guidance_pos, "custom after guidance");
|
||||
assert!(agents_pos > custom_pos, "agents.md after custom");
|
||||
assert!(memory_pos > agents_pos, "memory after agents.md");
|
||||
assert!(skills_pos > memory_pos, "skills after memory");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// TC-4.3-08: Tool guidance present in plan mode
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn tc_4_3_08_guidance_in_plan_mode() {
|
||||
let result = build_system_prompt(
|
||||
&mut SystemPromptCache::new(),
|
||||
None,
|
||||
"/tmp",
|
||||
"test-model",
|
||||
&[],
|
||||
None,
|
||||
None,
|
||||
true,
|
||||
false,
|
||||
false, // browser_enabled
|
||||
);
|
||||
assert!(
|
||||
result.contains("# Using your tools"),
|
||||
"tool guidance should be present even in plan mode"
|
||||
);
|
||||
// Plan mode instructions should also be present
|
||||
assert!(
|
||||
result.contains("plan") || result.contains("Plan"),
|
||||
"plan mode instructions should coexist with tool guidance"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user