๐Ÿš€Transform your business with AI-powered process optimization
Architecture
๐Ÿ’ก Design Patterns
Software Design Patterns
Command Pattern

Command Pattern

The Command Pattern encapsulates agent requests as objects, enabling parameterization, queuing, logging, and undo operations for AI agent actions.

Pattern Overview

This pattern turns requests into stand-alone objects containing all information about the request, allowing you to queue operations, log them, and support undo.

Structure

// Command trait
pub trait Command {
    fn execute(&self) -> Result<String, String>;
    fn undo(&self) -> Result<String, String>;
    fn get_description(&self) -> &str;
}
 
// Receiver - the object that performs the actual work
pub struct DataProcessor {
    pub data: Vec<String>,
}
 
impl DataProcessor {
    pub fn new() -> Self {
        Self { data: Vec::new() }
    }
 
    pub fn add_data(&mut self, item: String) -> Result<String, String> {
        self.data.push(item.clone());
        Ok(format!("Added: {}", item))
    }
 
    pub fn remove_data(&mut self, item: &str) -> Result<String, String> {
        if let Some(pos) = self.data.iter().position(|x| x == item) {
            self.data.remove(pos);
            Ok(format!("Removed: {}", item))
        } else {
            Err(format!("Item not found: {}", item))
        }
    }
}
 
// Concrete command implementations
pub struct AddDataCommand {
    data: String,
    description: String,
}
 
impl AddDataCommand {
    pub fn new(data: String) -> Self {
        let description = format!("Add data: {}", data);
        Self { data, description }
    }
}
 
impl Command for AddDataCommand {
    fn execute(&self) -> Result<String, String> {
        // In real implementation, would have reference to processor
        Ok(format!("Executing: Add {}", self.data))
    }
 
    fn undo(&self) -> Result<String, String> {
        Ok(format!("Undoing: Remove {}", self.data))
    }
 
    fn get_description(&self) -> &str {
        &self.description
    }
}
 
// Command invoker
pub struct AgentCommandInvoker {
    history: Vec<Box<dyn Command>>,
    current: usize,
}
 
impl AgentCommandInvoker {
    pub fn new() -> Self {
        Self {
            history: Vec::new(),
            current: 0,
        }
    }
 
    pub fn execute_command(&mut self, command: Box<dyn Command>) -> Result<String, String> {
        let result = command.execute();
        self.history.push(command);
        self.current += 1;
        result
    }
 
    pub fn undo(&mut self) -> Result<String, String> {
        if self.current > 0 {
            self.current -= 1;
            self.history[self.current].undo()
        } else {
            Err("Nothing to undo".to_string())
        }
    }
}

Usage Example

let mut invoker = AgentCommandInvoker::new();
let command = AddDataCommand::new("customer_data.csv".to_string());
 
// Execute command
invoker.execute_command(Box::new(command));
 
// Undo if needed
invoker.undo();

Benefits

  • Decoupling: Separates request initiation from execution
  • Undo/Redo: Built-in support for reversible operations
  • Logging: Easy to log all agent commands
  • Queuing: Commands can be queued and executed later

Use Cases

  • Agent task scheduling and execution
  • Implementing undo functionality in agent workflows
  • Logging agent actions for audit trails
  • Building macro commands from simple operations