Skip to content

Create a Custom Agent

This guide walks you through creating a custom domain agent using the amplihack-rs agent framework.

Prerequisites

  • amplihack-rs installed (cargo install amplihack)
  • Rust 2024 edition or later

Step 1: Add Dependencies

In your Cargo.toml:

[dependencies]
amplihack-agent-core = { path = "../amplihack-rs/crates/amplihack-agent-core" }
amplihack-domain-agents = { path = "../amplihack-rs/crates/amplihack-domain-agents" }
amplihack-memory = { path = "../amplihack-rs/crates/amplihack-memory" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

Step 2: Define Your Agent

Create a struct that implements the DomainAgent trait:

use amplihack_agent_core::{AgentConfig, AgentError, TaskResult};
use amplihack_domain_agents::{DomainAgent, EvalLevel, EvalScenario};

pub struct SecurityAuditor {
    model: String,
    memory: Option<Memory>,
}

impl SecurityAuditor {
    pub fn new(model: &str) -> Self {
        Self {
            model: model.to_string(),
            memory: None,
        }
    }
}

impl DomainAgent for SecurityAuditor {
    fn name(&self) -> &str {
        "security-auditor"
    }

    fn execute(&self, input: &str) -> Result<TaskResult, AgentError> {
        // Analyze the input for security issues
        let findings = analyze_security(input)?;

        Ok(TaskResult {
            output: format!("Found {} security issues", findings.len()),
            confidence: 0.9,
            metadata: [("findings_count".into(), serde_json::json!(findings.len()))]
                .into_iter()
                .collect(),
            memory_updates: Vec::new(),
        })
    }

    fn evaluate(&self, scenario: &EvalScenario) -> Result<TaskResult, AgentError> {
        self.execute(&scenario.input)
    }

    fn supported_levels(&self) -> &[EvalLevel] {
        &[EvalLevel::L1, EvalLevel::L2, EvalLevel::L3]
    }
}

Step 3: Add Memory Integration

Give your agent persistent memory:

use amplihack_memory::{Memory, MemoryConfig, Backend, Topology};

impl SecurityAuditor {
    pub fn with_memory(model: &str, agent_name: &str) -> Result<Self, AgentError> {
        let memory = Memory::new(agent_name, MemoryConfig {
            backend: Backend::Cognitive,
            topology: Topology::Single,
            ..Default::default()
        })?;

        Ok(Self {
            model: model.to_string(),
            memory: Some(memory),
        })
    }

    pub fn audit_with_context(&self, code: &str) -> Result<TaskResult, AgentError> {
        // Recall previous findings for context
        if let Some(ref mem) = self.memory {
            let history = mem.recall("previous security findings")?;
            // Use history to inform current analysis...
        }

        let result = self.execute(code)?;

        // Store findings for future reference
        if let Some(ref mem) = self.memory {
            mem.remember(&result.output)?;
        }

        Ok(result)
    }
}

Step 4: Register with SkillInjector (Optional)

Add dynamic capabilities to your agent:

use amplihack_domain_agents::SkillInjector;

let mut injector = SkillInjector::new();

// Register a web search skill
injector.register("cve-lookup", Box::new(CveLookupSkill));

// Inject into your agent
let enhanced = injector.inject(Box::new(auditor))?;

Step 5: Evaluate Your Agent

Run your agent through the evaluation framework:

use amplihack_agent_eval::DomainEvalHarness;

let harness = DomainEvalHarness::new(vec![Box::new(auditor)]);
let report = harness.run_all()?;

for result in &report.results {
    println!("{}: {:.1}% (levels: {:?})",
        result.agent_name,
        result.score * 100.0,
        result.level_scores.keys().collect::<Vec<_>>()
    );
}

Step 6: Package as Standalone Agent

Use the goal agent generator to package:

use amplihack_agent_generator::GoalAgentPackager;

let packager = GoalAgentPackager::new(Some("./agents".into()));
let agent_dir = packager.package(&bundle)?;
println!("Packaged to: {}", agent_dir.display());

Complete Example

See examples/custom_security_agent.rs for a full working example that combines all these steps.