use async_trait::async_trait;
use super::{Planner, PlannerError};
use crate::llm::LlmRequest;
#[derive(Debug, Clone, Default)]
pub struct BuiltInPlanner {
custom_instruction: Option<String>,
}
impl BuiltInPlanner {
pub fn new() -> Self {
Self::default()
}
pub fn with_instruction(instruction: impl Into<String>) -> Self {
Self {
custom_instruction: Some(instruction.into()),
}
}
}
const DEFAULT_PLANNING_INSTRUCTION: &str = "\
Before taking any action, think step by step about what you need to do. \
Create a brief plan, then execute it. If you need to adjust your plan based \
on new information, explain your reasoning before changing course.";
#[async_trait]
impl Planner for BuiltInPlanner {
fn build_planning_instruction(
&self,
_request: &LlmRequest,
) -> Result<Option<String>, PlannerError> {
Ok(Some(self.custom_instruction.clone().unwrap_or_else(|| {
DEFAULT_PLANNING_INSTRUCTION.to_string()
})))
}
fn process_planning_response(
&self,
_response_text: &str,
) -> Result<Option<String>, PlannerError> {
Ok(None)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_instruction() {
let planner = BuiltInPlanner::new();
let request = LlmRequest::default();
let instruction = planner.build_planning_instruction(&request).unwrap();
assert!(instruction.is_some());
assert!(instruction.unwrap().contains("step by step"));
}
#[test]
fn custom_instruction() {
let planner = BuiltInPlanner::with_instruction("Plan carefully");
let request = LlmRequest::default();
let instruction = planner.build_planning_instruction(&request).unwrap();
assert_eq!(instruction.unwrap(), "Plan carefully");
}
#[test]
fn response_passthrough() {
let planner = BuiltInPlanner::new();
let result = planner.process_planning_response("some response").unwrap();
assert!(result.is_none());
}
}