Compare commits

...

3 Commits

4 changed files with 34 additions and 56 deletions

View File

@ -7,7 +7,7 @@ use crate::storage::{MemoryRepository, SchedulerJobRepository, SkillEventReposit
use crate::tools::{
BashTool, CalculatorTool, FileEditTool, FileReadTool, FileWriteTool,
HttpRequestTool, MemoryManageTool, MemorySearchTool,
SchedulerManageTool, SessionMessageSender, SessionSendTool, SkillActivateTool, SkillListTool,
SchedulerManageTool, SessionMessageSender, SessionSendTool, SkillActivateTool,
SkillManageTool, SubAgentRuntime, TaskTool, TimeTool,
ToolRegistry, WebFetchTool,
};
@ -102,9 +102,6 @@ impl ToolRegistryFactory {
self.skill_events.clone(),
));
}
if self.is_enabled("skill_list") {
registry.register(SkillListTool::new(self.skills.clone()));
}
if self.is_enabled("skill_manage") {
registry.register(SkillManageTool::new(self.skills.clone()));
}
@ -180,9 +177,6 @@ impl ToolRegistryFactory {
self.skill_events.clone(),
));
}
if self.is_enabled("skill_list") {
registry.register(SkillListTool::new(self.skills.clone()));
}
// 进度通知工具
if self.is_enabled("session_send") {

View File

@ -434,7 +434,23 @@ impl SkillCatalog {
}
let mut prompt = String::from(
"# 技能说明\n技能为特定任务提供专用说明和工作流。\n当任务匹配其描述时,使用 skill_activate 工具加载技能。\n技能不是工具名,即使技能名看起来像工具,也不能直接调用技能名。\n如果需要某个技能,必须先调用 tool skill_activate并传入 {\"name\": \"<skill-name>\"},再根据返回的技能说明执行。\n\n<available_skills>\n",
"# 技能系统Skills\n\n\
使\n\n\
## 使\n\n\
使\n\
- \n\
- \n\
- \n\n\
## 使\n\n\
1. ****: <available_skills> \n\
2. ****: \n\
3. ****: `skill_activate` name \n\
4. ****: skill_activate \n\n\
## \n\n\
- \n\
- skill_activate \n\
- \n\n\
<available_skills>\n",
);
for skill in &self.skills {

View File

@ -33,7 +33,7 @@ pub use session_send::{
};
pub use schema::{CleaningStrategy, SchemaCleanr};
pub use skill_activate::SkillActivateTool;
pub use skill_manage::{SkillListTool, SkillManageTool};
pub use skill_manage::SkillManageTool;
pub use task::{
DefaultSubAgentRuntime, InMemoryTaskRepository, SubAgentRuntime, SubAgentRuntimeConfig,
TaskError, TaskRepository, TaskTool,

View File

@ -10,22 +10,12 @@ pub struct SkillManageTool {
skills: Arc<SkillRuntime>,
}
pub struct SkillListTool {
skills: Arc<SkillRuntime>,
}
impl SkillManageTool {
pub fn new(skills: Arc<SkillRuntime>) -> Self {
Self { skills }
}
}
impl SkillListTool {
pub fn new(skills: Arc<SkillRuntime>) -> Self {
Self { skills }
}
}
#[async_trait]
impl Tool for SkillManageTool {
fn name(&self) -> &str {
@ -33,7 +23,16 @@ impl Tool for SkillManageTool {
}
fn description(&self) -> &str {
"Manage PicoBot skills stored under .picobot/skills or ~/.picobot/skills, while discovery also reads .agents/skills, ~/.agents/skills, .openclaw/skills, and ~/.openclaw/skills. Supports actions: list, get, create, update, delete, disable, reload."
"Manage PicoBot skills. Actions: list, get, create, update, delete, disable, reload.\n\n\
Skill Structure:\n\
- Folder name: kebab-case (lowercase with hyphens, e.g., 'my-cool-skill')\n\
- Required: SKILL.md with YAML frontmatter + Markdown body\n\
- Optional folders: scripts/, references/, assets/\n\
- Storage: .picobot/skills/{name}/SKILL.md or ~/.picobot/skills/{name}/SKILL.md\n\n\
Installing from Zip:\n\
- Extract skill folders to skills/ directory\n\
- If zip contains multiple skills, extract each subfolder separately\n\
- Final structure: skills/{skill-name}/SKILL.md"
}
fn parameters_schema(&self) -> serde_json::Value {
@ -52,7 +51,7 @@ impl Tool for SkillManageTool {
},
"name": {
"type": "string",
"description": "Skill name"
"description": "Skill folder name in kebab-case (e.g., 'my-cool-skill', 'code-review'). Must match the folder name under .picobot/skills/ or ~/.picobot/skills/"
},
"names": {
"type": "array",
@ -101,10 +100,6 @@ impl Tool for SkillManageTool {
};
let name = args.get("name").and_then(|v| v.as_str());
let names = match parse_disable_names(&args) {
Ok(names) => names,
Err(err) => return Ok(error_result(&err)),
};
let result = match action {
"list" => list_skills_payload(&self.skills),
@ -207,6 +202,10 @@ impl Tool for SkillManageTool {
Err(err) => return Ok(error_result(&err)),
},
"disable" => {
let names = match parse_disable_names(&args) {
Ok(names) => names,
Err(err) => return Ok(error_result(&err)),
};
let targets = &names;
let mut changes = Vec::new();
@ -241,37 +240,6 @@ impl Tool for SkillManageTool {
}
}
#[async_trait]
impl Tool for SkillListTool {
fn name(&self) -> &str {
"skill_list"
}
fn description(&self) -> &str {
"List currently discovered PicoBot skills as a read-only operation. Use this when you only need to inspect available skills without modifying them."
}
fn parameters_schema(&self) -> serde_json::Value {
json!({
"type": "object",
"properties": {},
"additionalProperties": false
})
}
fn read_only(&self) -> bool {
true
}
async fn execute(&self, _args: serde_json::Value) -> anyhow::Result<ToolResult> {
Ok(ToolResult {
success: true,
output: serde_json::to_string_pretty(&list_skills_payload(&self.skills))?,
error: None,
})
}
}
fn error_result(message: &str) -> ToolResult {
ToolResult {
success: false,