use std::sync::Arc;
use agent_base::{AgentResult, Tool, ToolContext, ToolControlFlow, ToolOutput};
use async_trait::async_trait;
use phi_agent::{
OpenAiClient, OutputFormat, PhiAgent, PhiAgentConfig, ReasoningEffort, SafetyConfig, base_agent_builder,
build_system_prompt, create_stdout_renderer,
};
use serde_json::{Value, json};
struct CalculatorTool;
#[async_trait]
impl Tool for CalculatorTool {
fn name(&self) -> &'static str {
"calculator"
}
fn definition(&self) -> Value {
json!({
"name": "calculator",
"description": "Evaluate a simple arithmetic expression",
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Math expression, e.g. '2 + 3 * 4'"
}
},
"required": ["expression"]
}
})
}
async fn call(&self, args: &Value, _ctx: &ToolContext) -> AgentResult<ToolOutput> {
let expr = args["expression"].as_str().unwrap_or("0");
let result = evaluate(expr);
Ok(ToolOutput {
summary: format!("{} = {}", expr, result),
control_flow: ToolControlFlow::Continue,
raw: None,
truncation: None,
})
}
}
fn evaluate(expr: &str) -> f64 {
let tokens: Vec<&str> = expr.split_whitespace().collect();
if tokens.is_empty() {
return 0.0;
}
let mut result: f64 = tokens[0].parse().unwrap_or(0.0);
let mut i = 1;
while i < tokens.len() {
let op = tokens[i];
let rhs: f64 = tokens.get(i + 1).and_then(|t| t.parse().ok()).unwrap_or(0.0);
match op {
"+" => result += rhs,
"-" => result -= rhs,
"*" => result *= rhs,
"/" if rhs != 0.0 => result /= rhs,
"/" => {},
_ => {},
}
i += 2;
}
result
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
let api_key = std::env::var("LLM_API_KEY")
.or_else(|_| std::env::var("OPENAI_API_KEY"))
.expect("Set LLM_API_KEY or OPENAI_API_KEY environment variable");
let model = std::env::var("LLM_MODEL").unwrap_or_else(|_| "opus".into());
let base_url = std::env::var("LLM_BASE_URL").unwrap_or_else(|_| "https://api.openai.com/v1".into());
let llm_client = Arc::new(OpenAiClient::new(api_key, model.clone(), Some(base_url)));
let builder = base_agent_builder(llm_client).system_prompt(build_system_prompt()).register_tool(CalculatorTool);
let agent = PhiAgent::build(
builder,
PhiAgentConfig {
model,
enable_thinking: true,
thinking_budget: None,
thinking_effort: ReasoningEffort::Medium,
safety: SafetyConfig::default(),
max_turns: None,
},
)?;
let session = agent.create_session().await;
let mut renderer =
create_stdout_renderer(&OutputFormat::Terminal { show_thinking: true, show_tool_args: true, color: true });
println!("Agent ready. Ask a math question!\n");
agent.run_turn(session, "What is (15 + 27) * 3?", |event| renderer.render(event)).await?;
Ok(())
}