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
77 lines
2.0 KiB
Rust
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()
|
|
}
|
|
}
|