feat: 更新记忆工具使用说明,增加高价值场景记录要求;优化技能索引提示格式,支持 XML 标记
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
parent
69364e484b
commit
42eb9f85d5
@ -43,7 +43,7 @@
|
||||
- 优先调用 memory_manage(action='put');同一 namespace/key 可直接覆盖更新。
|
||||
|
||||
|
||||
### 以下场景视为高价值加分
|
||||
### 以下场景视为高价值加分,必须记录记忆
|
||||
- 用户多次跟你交互去优化输出
|
||||
- 用户对你的纠正
|
||||
- 确定的事实,路径/地址/网址等
|
||||
|
||||
@ -160,6 +160,12 @@ impl WechatChannel {
|
||||
.map(ToOwned::to_owned);
|
||||
Ok(vec![media_item])
|
||||
}
|
||||
|
||||
async fn send_typing_indicator(bot: Arc<WeChatBot>, chat_id: &str) {
|
||||
if let Err(error) = bot.send_typing(chat_id).await {
|
||||
tracing::debug!(chat_id = %chat_id, error = %error, "Failed to send WeChat typing indicator");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -202,6 +208,8 @@ impl Channel for WechatChannel {
|
||||
let bot = bot_for_handler.clone();
|
||||
let channel_name_for_publish = channel_name.clone();
|
||||
tokio::spawn(async move {
|
||||
Self::send_typing_indicator(bot.clone(), &sender_id).await;
|
||||
|
||||
let media = match Self::download_inbound_media(bot, msg.clone()).await {
|
||||
Ok(media) => media,
|
||||
Err(error) => {
|
||||
|
||||
@ -429,18 +429,25 @@ impl SkillCatalog {
|
||||
}
|
||||
|
||||
let mut prompt = String::from(
|
||||
"You have access to skills discovered from local skill directories. Use a skill only when the user's request clearly matches the skill description.\nSkills are not tools. Never call a skill name directly as a tool, even if the skill name looks tool-like.\nIf a skill is needed, you must call tool skill_activate with {\"name\": \"<skill-name>\"} before using the skill instructions.\nDo not call <skill-name> directly. Always call skill_activate first.\nAvailable skills:\n",
|
||||
"技能为特定任务提供专用说明和工作流。\n当任务匹配其描述时,使用 skill_activate 工具加载技能。\n技能不是工具名,即使技能名看起来像工具,也不能直接调用技能名。\n如果需要某个技能,必须先调用 tool skill_activate,并传入 {\"name\": \"<skill-name>\"},再根据返回的技能说明执行。\n\n<available_skills>\n",
|
||||
);
|
||||
|
||||
for skill in self.skills.iter().take(self.max_listed_skills) {
|
||||
let line = format!("- {}: {}\n", skill.name, skill.description);
|
||||
if prompt.len() + line.len() > self.max_index_chars {
|
||||
prompt.push_str("- ... (truncated)\n");
|
||||
let entry = format!(
|
||||
" <skill>\n <name>{}</name>\n <description>{}</description>\n <location>{}</location>\n </skill>\n",
|
||||
xml_escape(&skill.name),
|
||||
xml_escape(&skill.description),
|
||||
xml_escape(&format!("file://{}", skill.path.display())),
|
||||
);
|
||||
if prompt.len() + entry.len() + "</available_skills>\n".len() > self.max_index_chars {
|
||||
prompt.push_str(" <truncated>true</truncated>\n");
|
||||
break;
|
||||
}
|
||||
prompt.push_str(&line);
|
||||
prompt.push_str(&entry);
|
||||
}
|
||||
|
||||
prompt.push_str("</available_skills>\n");
|
||||
|
||||
Some(prompt)
|
||||
}
|
||||
|
||||
@ -827,6 +834,13 @@ fn split_frontmatter(content: &str) -> Option<(&str, &str)> {
|
||||
Some((frontmatter, body))
|
||||
}
|
||||
|
||||
fn xml_escape(value: &str) -> String {
|
||||
value
|
||||
.replace('&', "&")
|
||||
.replace('<', "<")
|
||||
.replace('>', ">")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -925,6 +939,29 @@ mod tests {
|
||||
assert!(payload.contains("Step A"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_system_index_prompt_uses_available_skills_markup() {
|
||||
let catalog = SkillCatalog {
|
||||
skills: vec![Skill {
|
||||
name: "demo-skill".to_string(),
|
||||
description: "demo <skill> & usage".to_string(),
|
||||
body: String::new(),
|
||||
source: SkillSource::Project,
|
||||
path: PathBuf::from("/tmp/demo-skill/SKILL.md"),
|
||||
}],
|
||||
max_index_chars: 4000,
|
||||
max_listed_skills: 32,
|
||||
};
|
||||
|
||||
let prompt = catalog.system_index_prompt().unwrap();
|
||||
assert!(prompt.contains("<available_skills>"));
|
||||
assert!(prompt.contains("技能为特定任务提供专用说明和工作流。"));
|
||||
assert!(prompt.contains("<name>demo-skill</name>"));
|
||||
assert!(prompt.contains("<description>demo <skill> & usage</description>"));
|
||||
assert!(prompt.contains("<location>file:///tmp/demo-skill/SKILL.md</location>"));
|
||||
assert!(prompt.contains("</available_skills>"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_runtime_create_update_delete_reload() {
|
||||
let _lock = acquire_test_lock();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user