Files
zclaw_openfang/crates/zclaw-runtime/src/tool/builtin/execute_skill.rs
iven 9060935401 perf(runtime): Hermes Phase 1-3 — prompt caching + parallel tools + smart retry
Phase 1: Anthropic prompt caching
- Add cache_control ephemeral on system prompt blocks
- Track cache_creation/cache_read tokens in CompletionResponse + StreamChunk

Phase 2A: Parallel tool execution
- Add ToolConcurrency enum (ReadOnly/Exclusive/Interactive)
- JoinSet + Semaphore(3) for bounded parallel tool calls
- 7 tools annotated with correct concurrency level
- AtomicU32 for lock-free failure tracking in ToolErrorMiddleware

Phase 2B: Tool output pruning
- prune_tool_outputs() trims old ToolResult > 2000 chars to 500 chars
- Integrated into CompactionMiddleware before token estimation

Phase 3: Error classification + smart retry
- LlmErrorKind + ClassifiedLlmError for structured error mapping
- RetryDriver decorator with jittered exponential backoff
- Kernel wraps all LLM calls with RetryDriver
- CONTEXT_OVERFLOW recovery triggers emergency compaction in loop_runner
2026-04-24 08:39:56 +08:00

77 lines
2.0 KiB
Rust

//! Execute skill tool
use async_trait::async_trait;
use serde_json::{json, Value};
use zclaw_types::{Result, ZclawError};
use crate::tool::{Tool, ToolContext, ToolConcurrency};
pub struct ExecuteSkillTool;
impl ExecuteSkillTool {
pub fn new() -> Self {
Self
}
}
#[async_trait]
impl Tool for ExecuteSkillTool {
fn name(&self) -> &str {
"execute_skill"
}
fn description(&self) -> &str {
"Execute a skill by its ID. Skills are predefined capabilities that can be invoked with structured input."
}
fn input_schema(&self) -> Value {
json!({
"type": "object",
"properties": {
"skill_id": {
"type": "string",
"description": "The ID of the skill to execute"
},
"input": {
"type": "object",
"description": "The input parameters for the skill",
"additionalProperties": true
}
},
"required": ["skill_id"]
})
}
fn concurrency(&self) -> ToolConcurrency {
ToolConcurrency::Exclusive
}
async fn execute(&self, input: Value, context: &ToolContext) -> Result<Value> {
let skill_id = input["skill_id"].as_str()
.ok_or_else(|| ZclawError::InvalidInput("Missing 'skill_id' parameter".into()))?;
let skill_input = input.get("input").cloned().unwrap_or(json!({}));
// Get skill executor from context
let executor = context.skill_executor.as_ref()
.ok_or_else(|| ZclawError::ToolError("Skill executor not available".into()))?;
// Get session_id from context or use empty string
let session_id = context.session_id.as_deref().unwrap_or("");
// Execute the skill
executor.execute_skill(
skill_id,
&context.agent_id.to_string(),
session_id,
skill_input,
).await
}
}
impl Default for ExecuteSkillTool {
fn default() -> Self {
Self::new()
}
}