feat(phase4): complete zclaw-skills, zclaw-hands, zclaw-channels, zclaw-protocols 模块实现

This commit is contained in:
iven
2026-03-22 08:57:37 +08:00
parent 7abfca9d5c
commit 0ab2f7afda
24 changed files with 2060 additions and 0 deletions

View File

@@ -0,0 +1,147 @@
//! Skill definition and types
use serde::{Deserialize, Serialize};
use serde_json::Value;
use zclaw_types::{SkillId, Result};
/// Skill manifest definition
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SkillManifest {
/// Unique skill identifier
pub id: SkillId,
/// Human-readable name
pub name: String,
/// Skill description
pub description: String,
/// Skill version
pub version: String,
/// Skill author
#[serde(default)]
pub author: Option<String>,
/// Execution mode
pub mode: SkillMode,
/// Required capabilities
#[serde(default)]
pub capabilities: Vec<String>,
/// Input schema (JSON Schema)
#[serde(default)]
pub input_schema: Option<Value>,
/// Output schema (JSON Schema)
#[serde(default)]
pub output_schema: Option<Value>,
/// Tags for categorization
#[serde(default)]
pub tags: Vec<String>,
/// Whether the skill is enabled
#[serde(default = "default_enabled")]
pub enabled: bool,
}
fn default_enabled() -> bool { true }
/// Skill execution mode
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum SkillMode {
/// Prompt-only skill (no code execution)
PromptOnly,
/// Python script execution
Python,
/// Shell command execution
Shell,
/// WebAssembly execution
Wasm,
/// Native Rust execution
Native,
}
/// Skill execution context
#[derive(Debug, Clone)]
pub struct SkillContext {
/// Agent ID executing the skill
pub agent_id: String,
/// Session ID for the execution
pub session_id: String,
/// Working directory for execution
pub working_dir: Option<std::path::PathBuf>,
/// Environment variables
pub env: std::collections::HashMap<String, String>,
/// Timeout in seconds
pub timeout_secs: u64,
/// Whether to allow network access
pub network_allowed: bool,
/// Whether to allow file system access
pub file_access_allowed: bool,
}
impl Default for SkillContext {
fn default() -> Self {
Self {
agent_id: String::new(),
session_id: String::new(),
working_dir: None,
env: std::collections::HashMap::new(),
timeout_secs: 60,
network_allowed: false,
file_access_allowed: false,
}
}
}
/// Skill execution result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SkillResult {
/// Whether execution succeeded
pub success: bool,
/// Output data
pub output: Value,
/// Error message if failed
#[serde(default)]
pub error: Option<String>,
/// Execution duration in milliseconds
#[serde(default)]
pub duration_ms: Option<u64>,
/// Token usage if LLM was #[serde(default)]
pub tokens_used: Option<u32>,
}
impl SkillResult {
pub fn success(output: Value) -> Self {
Self {
success: true,
output,
error: None,
duration_ms: None,
tokens_used: None,
}
}
pub fn error(message: impl Into<String>) -> Self {
Self {
success: false,
output: Value::Null,
error: Some(message.into()),
duration_ms: None,
tokens_used: None,
}
}
}
/// Skill definition with execution logic
#[async_trait::async_trait]
pub trait Skill: Send + Sync {
/// Get the skill manifest
fn manifest(&self) -> &SkillManifest;
/// Execute the skill with given input
async fn execute(&self, context: &SkillContext, input: Value) -> Result<SkillResult>;
/// Validate input against schema
fn validate_input(&self, input: &Value) -> Result<()> {
// Basic validation - can be overridden
if input.is_null() {
return Err(zclaw_types::ZclawError::InvalidInput("Input cannot be null".into()));
}
Ok(())
}
}