175 lines
6.2 KiB
Rust
175 lines
6.2 KiB
Rust
use super::types::SubagentDef;
|
||
use crate::config::LLMProviderConfig;
|
||
|
||
/// 子代理系统提示词构建器
|
||
pub struct SubagentPromptBuilder;
|
||
|
||
impl SubagentPromptBuilder {
|
||
/// 构建子代理系统提示词(包含系统环境信息和技能索引)
|
||
pub fn build(
|
||
def: &SubagentDef,
|
||
description: &str,
|
||
prompt: &str,
|
||
config: &LLMProviderConfig,
|
||
skills_index: Option<&str>,
|
||
) -> String {
|
||
let base_prompt = Self::interpolate_template(def, description, prompt);
|
||
let env_info = crate::agent::generate_system_env_prompt(config);
|
||
|
||
// 组合提示词:基础 + 环境 + 技能索引(可选)
|
||
match skills_index {
|
||
Some(index) if !index.is_empty() => {
|
||
format!("{}\n\n{}\n\n{}", base_prompt, env_info, index)
|
||
}
|
||
_ => format!("{}\n\n{}", base_prompt, env_info),
|
||
}
|
||
}
|
||
|
||
/// 构建恢复任务的提示词
|
||
pub fn build_resume_prompt(session_description: &str, additional_prompt: &str) -> String {
|
||
format!(
|
||
"你正在继续执行一个之前创建的子代理任务。\n\n\
|
||
任务描述: {}\n\n\
|
||
继续执行指令: {}\n\n\
|
||
你应该:\n\
|
||
1. 回顾之前的工作进度(如果已有历史)\n\
|
||
2. 继续完成任务,不要偏离目标\n\
|
||
3. 完成后给出简洁的总结\n\
|
||
4. 不要尝试创建新的子代理任务\n\n\
|
||
注意: 你在一个独立的执行上下文中,没有访问主对话历史的权限。",
|
||
session_description, additional_prompt
|
||
)
|
||
}
|
||
|
||
/// 插值提示词模板
|
||
fn interpolate_template(def: &SubagentDef, description: &str, prompt: &str) -> String {
|
||
// 自定义子代理使用通用模板
|
||
let base = if def.prompt_template.is_empty() {
|
||
"你是一个专注的子代理,正在执行一个独立任务。\n\n\
|
||
任务描述: {{description}}\n\n\
|
||
你应该:\n\
|
||
1. 专注于完成任务,不要偏离目标\n\
|
||
2. 使用可用的工具进行必要操作\n\
|
||
3. 完成后给出简洁的总结\n\
|
||
4. 当任务复杂度较高时,可以使用 `task` 工具创建子代理来处理独立子任务\n\n\
|
||
任务追踪:\n\
|
||
你可以使用 `todo_write` 工具追踪子任务进度。规则:同一时间只有一个 in_progress,完成后再标记下一个,3步以上才使用。\n\n\
|
||
注意: 你没有访问主对话历史的权限,这是一个独立的执行上下文。"
|
||
} else {
|
||
&def.prompt_template
|
||
};
|
||
|
||
let mut result = base
|
||
.replace("{{description}}", description)
|
||
.replace("{{prompt}}", prompt);
|
||
|
||
if let Some(ref body) = def.body {
|
||
result.push_str("\n\n");
|
||
result.push_str(body);
|
||
}
|
||
|
||
result
|
||
}
|
||
}
|
||
|
||
/// 从子代理输出提取简洁摘要
|
||
pub fn extract_summary(content: &str) -> String {
|
||
// 取第一段或前 500 字符
|
||
let first_paragraph = content
|
||
.lines()
|
||
.take_while(|line| !line.trim().is_empty())
|
||
.collect::<Vec<_>>()
|
||
.join("\n");
|
||
|
||
if first_paragraph.len() > 500 {
|
||
first_paragraph.chars().take(500).collect()
|
||
} else if first_paragraph.is_empty() {
|
||
content.chars().take(200).collect()
|
||
} else {
|
||
first_paragraph
|
||
}
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
use crate::tools::task::types::SubagentSource;
|
||
|
||
fn test_def() -> SubagentDef {
|
||
SubagentDef {
|
||
name: "general".to_string(),
|
||
description: "测试".to_string(),
|
||
prompt_template: "任务: {{description}}\n指令: {{prompt}}".to_string(),
|
||
body: None,
|
||
allowed_tools: None,
|
||
max_execution_secs: None,
|
||
source: SubagentSource::Builtin,
|
||
path: None,
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn test_interpolates_template() {
|
||
let def = test_def();
|
||
let result = SubagentPromptBuilder::build(
|
||
&def,
|
||
"审查代码",
|
||
"检查安全漏洞",
|
||
&LLMProviderConfig {
|
||
provider_type: "openai".to_string(),
|
||
name: "test".to_string(),
|
||
base_url: "http://localhost".to_string(),
|
||
api_key: "test".to_string(),
|
||
extra_headers: std::collections::HashMap::new(),
|
||
llm_timeout_secs: 120,
|
||
memory_maintenance_timeout_secs: 600,
|
||
model_id: "test".to_string(),
|
||
temperature: None,
|
||
max_tokens: None,
|
||
context_window_tokens: None,
|
||
model_extra: std::collections::HashMap::new(),
|
||
max_tool_iterations: 1,
|
||
tool_result_max_chars: 1000,
|
||
context_tool_result_trim_chars: 1000,
|
||
max_images_in_context: 1,
|
||
max_image_age_rounds: 10,
|
||
},
|
||
None,
|
||
);
|
||
assert!(result.contains("任务: 审查代码"));
|
||
assert!(result.contains("指令: 检查安全漏洞"));
|
||
}
|
||
|
||
#[test]
|
||
fn test_appends_body() {
|
||
let mut def = test_def();
|
||
def.body = Some("额外指令".to_string());
|
||
let result = SubagentPromptBuilder::build(
|
||
&def,
|
||
"描述",
|
||
"指令",
|
||
&LLMProviderConfig {
|
||
provider_type: "openai".to_string(),
|
||
name: "test".to_string(),
|
||
base_url: "http://localhost".to_string(),
|
||
api_key: "test".to_string(),
|
||
extra_headers: std::collections::HashMap::new(),
|
||
llm_timeout_secs: 120,
|
||
memory_maintenance_timeout_secs: 600,
|
||
model_id: "test".to_string(),
|
||
temperature: None,
|
||
max_tokens: None,
|
||
context_window_tokens: None,
|
||
model_extra: std::collections::HashMap::new(),
|
||
max_tool_iterations: 1,
|
||
tool_result_max_chars: 1000,
|
||
context_tool_result_trim_chars: 1000,
|
||
max_images_in_context: 1,
|
||
max_image_age_rounds: 10,
|
||
},
|
||
None,
|
||
);
|
||
assert!(result.contains("额外指令"));
|
||
}
|
||
}
|