lmm-derive 0.0.2

Proc-macro derive crates for the lmm agent framework.
Documentation

⚙️ lmm-derive

Crates.io Docs.rs MIT License

lmm-derive is the procedural macro crate for the lmm workspace. It provides the #[derive(Auto)] macro that generates full Agent, Functions, and AsyncFunctions implementations for any custom agent struct.

🤔 What does this crate provide?

The single export is the Auto derive macro. Placing #[derive(Auto)] on a struct that contains agent: LmmAgent automatically generates:

  • impl Agent for MyAgent: delegates persona(), behavior(), status(), memory(), etc. to the inner agent: LmmAgent field.
  • impl Functions for MyAgent: delegates get_agent().
  • #[async_trait] impl AsyncFunctions for MyAgent: provides generate, search, save_ltm, get_ltm, ltm_context backed by the TextPredictor symbolic engine and optionally DuckDuckGo.

No LLM provider, no API key, no training.

📦 Installation

This crate is automatically pulled in when you use lmm-agent:

[dependencies]
lmm-agent = "0.0.2"

🚀 Usage

Minimum required struct

Your struct only needs one field, agent: LmmAgent:

use lmm_agent::prelude::*;

#[derive(Debug, Default, Auto)]
pub struct MyAgent {
    pub agent: LmmAgent,
}

#[async_trait]
impl Executor for MyAgent {
    async fn execute<'a>(
        &'a mut self,
        _task:      &'a mut Task,
        _execute:    bool,
        _browse:     bool,
        _max_tries:  u64,
    ) -> Result<()> {
        // Custom logic here...
        Ok(())
    }
}

You can instantiate it with zero field repetition:

let agent = MyAgent::new("My Persona".into(), "My mission.".into());

Adding custom fields

Fields beyond agent: LmmAgent are ignored by Auto and are freely available for domain-specific data:

use lmm_agent::prelude::*;
use std::collections::HashMap;

#[derive(Debug, Default, Auto)]
pub struct DataAgent {
    pub agent:  LmmAgent,
    pub db_url: String,
    pub cache:  HashMap<String, String>,
}

#[async_trait]
impl Executor for DataAgent {
    async fn execute<'a>(
        &'a mut self, _task: &'a mut Task,
        _execute: bool, _browse: bool, _max_tries: u64,
    ) -> Result<()> { Ok(()) }
}

🔍 What the macro generates

For a struct called MyAgent the macro emits approximately:

impl Agent for MyAgent {
    fn new(persona: Cow<'static, str>, behavior: Cow<'static, str>) -> Self {
        let mut s = Self::default();
        s.agent = LmmAgent::new(persona, behavior);
        s
    }
    fn persona(&self)    -> &str          { &self.agent.persona }
    fn behavior(&self)   -> &str          { &self.agent.behavior }
    fn status(&self)     -> &Status       { &self.agent.status }
    fn memory(&self)     -> &Vec<Message> { &self.agent.memory }
    // ... all other Agent trait methods delegate to self.agent
}

impl Functions for MyAgent {
    fn get_agent(&self) -> &LmmAgent { &self.agent }
}

#[async_trait]
impl AsyncFunctions for MyAgent {
    async fn generate(&mut self, prompt: &str) -> Result<String> { ... }
    async fn search(&self, query: &str, limit: usize) -> Result<String> { ... }
    async fn save_ltm(&mut self, msg: Message) -> Result<()> { ... }
    async fn get_ltm(&self) -> Result<Vec<Message>> { ... }
    async fn ltm_context(&self) -> String { ... }
}

📄 License

Licensed under the MIT License.