use llm_toolkit::define_intent;
use llm_toolkit::intent::expandable::{Expandable, Selectable, SelectionRegistry};
#[define_intent]
#[intent(
prompt = r#"
Select an appropriate action based on the user's request.
Available actions:
{{ actions_doc }}
User request: {{ user_request }}
Respond with: <action>ACTION_NAME</action>
"#,
extractor_tag = "action"
)]
#[derive(Debug, Clone, PartialEq)]
pub enum AssistantAction {
#[expand(template = "Search the web for: {{ query }}\nReturn top 3 results.")]
WebSearch { query: String },
#[expand(template = "Read the file at path: {{ path }}\nReturn the contents.")]
FileRead { path: String },
#[expand(
template = "Write to file: {{ path }}\n\nContent:\n{{ content }}\n\nConfirm when done."
)]
FileWrite { path: String, content: String },
#[expand(template = "Calculate: {{ expression }}\nReturn the numeric result.")]
Calculate { expression: String },
SendMessage {
_recipient: String,
_message: String,
},
}
impl std::str::FromStr for AssistantAction {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.trim() {
"WebSearch" => Ok(AssistantAction::WebSearch {
query: String::new(),
}),
"FileRead" => Ok(AssistantAction::FileRead {
path: String::new(),
}),
"FileWrite" => Ok(AssistantAction::FileWrite {
path: String::new(),
content: String::new(),
}),
"Calculate" => Ok(AssistantAction::Calculate {
expression: String::new(),
}),
"SendMessage" => Ok(AssistantAction::SendMessage {
_recipient: String::new(),
_message: String::new(),
}),
_ => Err(format!("Unknown action: {}", s)),
}
}
}
fn main() {
println!("=== Expandable Macro Integration Example ===\n");
let mut registry = SelectionRegistry::new();
registry.register(AssistantAction::WebSearch {
query: "Rust programming".to_string(),
});
registry.register(AssistantAction::FileRead {
path: "/tmp/example.txt".to_string(),
});
registry.register(AssistantAction::FileWrite {
path: "/tmp/output.txt".to_string(),
content: "Hello, World!".to_string(),
});
registry.register(AssistantAction::Calculate {
expression: "2 + 2".to_string(),
});
registry.register(AssistantAction::SendMessage {
_recipient: "user".to_string(),
_message: "Task complete".to_string(),
});
println!("Registered {} actions\n", registry.len());
println!("=== Testing Selectable Trait ===\n");
let search_action = AssistantAction::WebSearch {
query: "OpenAI GPT".to_string(),
};
println!("Action: {:?}", search_action);
println!("Selection ID: {}", search_action.selection_id());
println!("Description: {}\n", search_action.description());
println!("=== Testing Expandable Trait ===\n");
let actions = vec![
AssistantAction::WebSearch {
query: "Rust async".to_string(),
},
AssistantAction::FileRead {
path: "/etc/hosts".to_string(),
},
AssistantAction::Calculate {
expression: "10 * 5 + 3".to_string(),
},
AssistantAction::SendMessage {
_recipient: "admin".to_string(),
_message: "Process complete".to_string(),
},
];
for action in &actions {
println!("Action: {}", action.selection_id());
let expanded = action.expand();
println!("Expanded:\n{}\n", expanded.to_text());
println!("---\n");
}
println!("=== Registry Prompt Section ===\n");
let prompt_section = registry.to_prompt_section();
println!("{}", prompt_section);
println!("\n=== Example Complete ===");
println!("\nKey takeaways:");
println!("1. #[expand(template = \"...\")] automatically implements Expandable");
println!("2. Selectable is automatically implemented using variant names");
println!("3. Template can use field names as {{ field_name }}");
println!("4. Variants without #[expand] use default expansion");
}