use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Expr, Ident, LitStr, Token, parse::{Parse, ParseStream}};
struct SimpleAgentDef {
name: LitStr,
instructions: LitStr,
provider: Expr,
tools: Vec<Ident>,
}
impl Parse for SimpleAgentDef {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut name = None;
let mut instructions = None;
let mut provider = None;
let mut tools = Vec::new();
while !input.is_empty() {
let key: Ident = input.parse()?;
let _: Token![:] = input.parse()?;
match key.to_string().as_str() {
"name" => {
name = Some(input.parse::<LitStr>()?);
},
"instructions" => {
instructions = Some(input.parse::<LitStr>()?);
},
"provider" => {
provider = Some(input.parse::<Expr>()?);
},
"tools" => {
let tools_content;
let _ = syn::bracketed!(tools_content in input);
while !tools_content.is_empty() {
tools.push(tools_content.parse::<Ident>()?);
if tools_content.peek(Token![,]) {
let _: Token![,] = tools_content.parse()?;
}
}
},
_ => {
return Err(syn::Error::new(key.span(), format!("Unknown field '{}' in agent definition", key)));
}
}
if input.peek(Token![,]) {
let _: Token![,] = input.parse()?;
}
}
let name = name.ok_or_else(|| syn::Error::new(input.span(), "Missing 'name' field"))?;
let instructions = instructions.ok_or_else(|| syn::Error::new(input.span(), "Missing 'instructions' field"))?;
let provider = provider.ok_or_else(|| syn::Error::new(input.span(), "Missing 'provider' field"))?;
Ok(SimpleAgentDef {
name,
instructions,
provider,
tools,
})
}
}
pub fn agent(input: TokenStream) -> TokenStream {
let agent_def = parse_macro_input!(input as SimpleAgentDef);
let agent_name = &agent_def.name;
let instructions = &agent_def.instructions;
let provider_expr = &agent_def.provider;
let tool_registrations: Vec<_> = agent_def.tools.iter().map(|tool_name| {
quote! {
agent.add_tool(#tool_name()).expect(&format!("Failed to add tool '{}' to agent", stringify!(#tool_name)));
}
}).collect();
let expanded = quote! {
{
use lumosai_core::agent::create_basic_agent;
use lumosai_core::llm::LlmProvider;
use std::sync::Arc;
let llm_provider: Arc<dyn LlmProvider> = Arc::new(#provider_expr);
let mut agent = create_basic_agent(
#agent_name.to_string(),
#instructions.to_string(),
llm_provider
);
#(#tool_registrations)*
agent
}
};
TokenStream::from(expanded)
}