zeroclaw/crates/robot-kit/src/traits.rs
Lumi-node 0dfc707c49 feat: add zeroclaw-robot-kit crate for AI-powered robotics
Standalone robot toolkit providing AI agents with physical world interaction.

Features:
- 6 tools: drive, look, listen, speak, sense, emote
- Multiple backends: ROS2, serial, GPIO, mock
- Independent SafetyMonitor with E-stop, collision avoidance
- Designed for Raspberry Pi 5 + Ollama offline operation
- 55 unit/integration tests
- Complete Pi 5 hardware setup guide
2026-02-18 14:19:17 +08:00

123 lines
3.4 KiB
Rust

//! Tool trait definition
//!
//! This defines the interface that all robot tools implement.
//! It is compatible with ZeroClaw's Tool trait but standalone.
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use serde_json::Value;
/// Result of a tool execution
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolResult {
/// Whether the tool executed successfully
pub success: bool,
/// Output from the tool (human-readable)
pub output: String,
/// Error message if failed
pub error: Option<String>,
}
impl ToolResult {
/// Create a successful result
pub fn success(output: impl Into<String>) -> Self {
Self {
success: true,
output: output.into(),
error: None,
}
}
/// Create a failed result
pub fn error(error: impl Into<String>) -> Self {
Self {
success: false,
output: String::new(),
error: Some(error.into()),
}
}
/// Create a failed result with partial output
pub fn partial(output: impl Into<String>, error: impl Into<String>) -> Self {
Self {
success: false,
output: output.into(),
error: Some(error.into()),
}
}
}
/// Description of a tool for LLM function calling
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolSpec {
/// Tool name (used in function calls)
pub name: String,
/// Human-readable description
pub description: String,
/// JSON Schema for parameters
pub parameters: Value,
}
/// Core tool trait
///
/// Implement this trait to create a new tool that can be used
/// by an AI agent to interact with the robot hardware.
///
/// # Example
///
/// ```rust,ignore
/// use zeroclaw_robot_kit::{Tool, ToolResult};
/// use async_trait::async_trait;
/// use serde_json::{json, Value};
///
/// pub struct BeepTool;
///
/// #[async_trait]
/// impl Tool for BeepTool {
/// fn name(&self) -> &str { "beep" }
///
/// fn description(&self) -> &str { "Make a beep sound" }
///
/// fn parameters_schema(&self) -> Value {
/// json!({
/// "type": "object",
/// "properties": {
/// "frequency": { "type": "number", "description": "Hz" }
/// }
/// })
/// }
///
/// async fn execute(&self, args: Value) -> anyhow::Result<ToolResult> {
/// let freq = args["frequency"].as_f64().unwrap_or(440.0);
/// // Play beep...
/// Ok(ToolResult::success(format!("Beeped at {}Hz", freq)))
/// }
/// }
/// ```
#[async_trait]
pub trait Tool: Send + Sync {
/// Tool name (used in LLM function calling)
fn name(&self) -> &str;
/// Human-readable description of what this tool does
fn description(&self) -> &str;
/// JSON Schema describing the tool's parameters
///
/// This is used by the LLM to understand how to call the tool.
fn parameters_schema(&self) -> Value;
/// Execute the tool with the given arguments
///
/// Arguments are passed as JSON matching the parameters_schema.
async fn execute(&self, args: Value) -> anyhow::Result<ToolResult>;
/// Get the full specification for LLM registration
fn spec(&self) -> ToolSpec {
ToolSpec {
name: self.name().to_string(),
description: self.description().to_string(),
parameters: self.parameters_schema(),
}
}
}