Skip to main content

lmm_derive/
lib.rs

1// Copyright 2026 Mahmoud Harmouch.
2//
3// Licensed under the MIT license
4// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
5// option. This file may not be copied, modified, or distributed
6// except according to those terms.
7
8//! # `lmm-derive`
9//!
10//! Proc-macro crates for the `lmm` agent framework.
11//!
12//! ## Derives
13//!
14//! - [`Auto`] - Generates `impl Agent`, `impl Functions`, and
15//!   `#[async_trait] impl AsyncFunctions` for any struct that contains an
16//!   `agent: LmmAgent` field. The struct must also `impl Executor`.
17//!
18//! ## Macros
19//!
20//! See the `agents!` macro re-exported from `lmm_agent`.
21//!
22//! ## Attribution
23//!
24//! The `Auto` derive is adapted from the `autogpt` crate's `auto-derive`:
25//! <https://github.com/wiseaidotdev/autogpt/blob/main/auto-derive/src/lib.rs>
26
27extern crate proc_macro;
28
29use proc_macro::TokenStream;
30use quote::quote;
31use syn::{DeriveInput, parse_macro_input};
32
33/// Derives `Agent`, `Functions`, and `AsyncFunctions` for a struct that:
34///
35/// - Contains a field named `agent` of type `LmmAgent`.
36/// - Implements the `Executor` trait.
37///
38/// This macro is adapted from the `autogpt` project's `auto-derive` crate:
39/// <https://github.com/wiseaidotdev/autogpt/blob/main/auto-derive/src/lib.rs>
40///
41/// # Example
42///
43/// ```rust,ignore
44/// use lmm_agent::prelude::*;
45///
46/// // Minimum required struct - only `agent: LmmAgent`.
47/// #[derive(Debug, Default, Auto)]
48/// pub struct MyAgent {
49///     pub agent: LmmAgent,
50/// }
51///
52/// #[async_trait]
53/// impl Executor for MyAgent {
54///     async fn execute<'a>(
55///         &'a mut self,
56///         _task: &'a mut Task,
57///         _execute: bool,
58///         _browse: bool,
59///         _max_tries: u64,
60///     ) -> Result<()> {
61///         // Custom logic here...
62///         Ok(())
63///     }
64/// }
65/// ```
66#[proc_macro_derive(Auto)]
67pub fn derive_auto(input: TokenStream) -> TokenStream {
68    let input = parse_macro_input!(input as DeriveInput);
69    let name = &input.ident;
70
71    let expanded = quote! {
72        impl ::lmm_agent::traits::agent::Agent for #name {
73            fn new(
74                persona: ::std::borrow::Cow<'static, str>,
75                behavior: ::std::borrow::Cow<'static, str>,
76            ) -> Self {
77                let mut s = Self::default();
78                s.agent = ::lmm_agent::agent::LmmAgent::new(persona, behavior);
79                s
80            }
81
82            fn update(&mut self, status: ::lmm_agent::types::Status) {
83                self.agent.update(status);
84            }
85
86            fn persona(&self) -> &str {
87                &self.agent.persona
88            }
89
90            fn behavior(&self) -> &str {
91                &self.agent.behavior
92            }
93
94            fn status(&self) -> &::lmm_agent::types::Status {
95                &self.agent.status
96            }
97
98            fn memory(&self) -> &::std::vec::Vec<::lmm_agent::types::Message> {
99                &self.agent.memory
100            }
101
102            fn tools(&self) -> &::std::vec::Vec<::lmm_agent::types::Tool> {
103                &self.agent.tools
104            }
105
106            fn knowledge(&self) -> &::lmm_agent::types::Knowledge {
107                &self.agent.knowledge
108            }
109
110            fn planner(&self) -> ::std::option::Option<&::lmm_agent::types::Planner> {
111                self.agent.planner.as_ref()
112            }
113
114            fn profile(&self) -> &::lmm_agent::types::Profile {
115                &self.agent.profile
116            }
117
118            fn reflection(&self) -> ::std::option::Option<&::lmm_agent::types::Reflection> {
119                self.agent.reflection.as_ref()
120            }
121
122            fn scheduler(&self) -> ::std::option::Option<&::lmm_agent::types::TaskScheduler> {
123                self.agent.scheduler.as_ref()
124            }
125
126            fn capabilities(&self) -> &::std::collections::HashSet<::lmm_agent::types::Capability> {
127                &self.agent.capabilities
128            }
129
130            fn context(&self) -> &::lmm_agent::types::ContextManager {
131                &self.agent.context
132            }
133
134            fn tasks(&self) -> &::std::vec::Vec<::lmm_agent::types::Task> {
135                &self.agent.tasks
136            }
137
138            fn memory_mut(&mut self) -> &mut ::std::vec::Vec<::lmm_agent::types::Message> {
139                &mut self.agent.memory
140            }
141
142            fn planner_mut(&mut self) -> ::std::option::Option<&mut ::lmm_agent::types::Planner> {
143                self.agent.planner.as_mut()
144            }
145
146            fn context_mut(&mut self) -> &mut ::lmm_agent::types::ContextManager {
147                &mut self.agent.context
148            }
149        }
150
151        impl ::lmm_agent::traits::functions::Functions for #name {
152            fn get_agent(&self) -> &::lmm_agent::agent::LmmAgent {
153                &self.agent
154            }
155        }
156
157        #[async_trait]
158        impl ::lmm_agent::traits::functions::AsyncFunctions for #name {
159            async fn execute<'a>(
160                &'a mut self,
161                tasks: &'a mut Task,
162                execute: bool,
163                browse: bool,
164                max_tries: u64,
165            ) -> Result<()> {
166                <#name as ::lmm_agent::traits::functions::Executor>::execute(
167                    self, tasks, execute, browse, max_tries,
168                )
169                .await
170            }
171
172            async fn save_ltm(
173                &mut self,
174                communication: Message,
175            ) -> Result<()> {
176                self.agent.long_term_memory.push(communication);
177                Ok(())
178            }
179
180            async fn get_ltm(&self) -> Result<Vec<Message>> {
181                Ok(self.agent.long_term_memory.clone())
182            }
183
184            async fn ltm_context(&self) -> String {
185                self.agent
186                    .long_term_memory
187                    .iter()
188                    .map(|c| format!("{}: {}", c.role, c.content))
189                    .collect::<Vec<_>>()
190                    .join("\n")
191            }
192
193            async fn generate(&mut self, request: &str) -> Result<String> {
194                self.agent.generate(request).await
195            }
196
197            async fn search(
198                &self,
199                query: &str,
200                limit: usize,
201            ) -> Result<String> {
202                self.agent.search(query, limit).await
203            }
204        }
205    };
206
207    TokenStream::from(expanded)
208}