ai-agent-sdk 0.4.0

Idiomatic agent sdk inspired by the claude code source leak
Documentation
//! Plan mode tools.
//!
//! Provides tools for structured planning workflow.

use crate::types::*;

/// EnterPlanMode tool - enter structured planning mode
pub struct EnterPlanModeTool;

impl EnterPlanModeTool {
    pub fn new() -> Self {
        Self
    }

    pub fn input_schema(&self) -> ToolInputSchema {
        ToolInputSchema {
            schema_type: "object".to_string(),
            properties: serde_json::json!({
                "allowedPrompts": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "Prompt-based permissions needed to implement the plan"
                }
            }),
            required: None,
        }
    }

    pub async fn execute(&self, input: serde_json::Value, _context: &ToolContext) -> Result<ToolResult, crate::error::AgentError> {
        let allowed = input["allowedPrompts"].as_array()
            .map(|arr| arr.iter().filter_map(|v| v.as_str()).collect::<Vec<_>>())
            .unwrap_or_default();

        let response = if allowed.is_empty() {
            "Entering plan mode...\nNote: Full implementation would explore codebase and design an implementation approach for user approval.".to_string()
        } else {
            format!(
                "Entering plan mode with permissions: {:?}\nNote: Full implementation would explore codebase and design an implementation approach for user approval.",
                allowed
            )
        };

        Ok(ToolResult {
            result_type: "text".to_string(),
            tool_use_id: "enter_plan_mode".to_string(),
            content: response,
            is_error: Some(false),
        })
    }
}

impl Default for EnterPlanModeTool {
    fn default() -> Self {
        Self::new()
    }
}

/// ExitPlanMode tool - exit planning mode
pub struct ExitPlanModeTool;

impl ExitPlanModeTool {
    pub fn new() -> Self {
        Self
    }

    pub fn input_schema(&self) -> ToolInputSchema {
        ToolInputSchema {
            schema_type: "object".to_string(),
            properties: serde_json::json!({}),
            required: None,
        }
    }

    pub async fn execute(&self, _input: serde_json::Value, _context: &ToolContext) -> Result<ToolResult, crate::error::AgentError> {
        let response = "Exiting plan mode...\nNote: Full implementation would present the plan to the user for approval.".to_string();

        Ok(ToolResult {
            result_type: "text".to_string(),
            tool_use_id: "exit_plan_mode".to_string(),
            content: response,
            is_error: Some(false),
        })
    }
}

impl Default for ExitPlanModeTool {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_enter_plan_mode_schema() {
        let tool = EnterPlanModeTool::new();
        let schema = tool.input_schema();
        assert!(schema.properties.get("allowedPrompts").is_some());
    }

    #[test]
    fn test_exit_plan_mode_schema() {
        let tool = ExitPlanModeTool::new();
        let schema = tool.input_schema();
        assert_eq!(schema.schema_type, "object");
    }
}