use std::sync::atomic::AtomicU32;
use agent_base::{AgentResult, Middleware, PostLlmCtx, PreLlmCtx, UserMessageCtx};
use async_trait::async_trait;
use phi_agent::{PhiAgent, PhiAgentConfig, ReasoningEffort, SafetyConfig, base_agent_builder, build_system_prompt};
#[path = "../common/mod.rs"]
mod common;
struct LoggingMiddleware {
turn_count: AtomicU32,
}
impl LoggingMiddleware {
fn new() -> Self {
Self { turn_count: AtomicU32::new(0) }
}
}
#[async_trait]
impl Middleware for LoggingMiddleware {
async fn on_user_message(&self, ctx: &mut UserMessageCtx) -> AgentResult<()> {
let turn = self.turn_count.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
println!(
"[middleware] on_user_message — turn={}, session={}, input_len={}",
turn,
ctx.session_id.id,
ctx.user_input.len()
);
Ok(())
}
async fn on_pre_llm(&self, ctx: &mut PreLlmCtx) -> AgentResult<()> {
println!(
"[middleware] on_pre_llm — session={}, messages={}, tools={}",
ctx.session_id.id,
ctx.messages.len(),
ctx.tools.len()
);
Ok(())
}
async fn on_post_llm(&self, ctx: &mut PostLlmCtx) -> AgentResult<()> {
println!(
"[middleware] on_post_llm — is_tool_call={}, text_len={}, turn={}",
ctx.is_tool_call,
ctx.full_text.len(),
ctx.turn_count
);
Ok(())
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
let llm_client = common::client();
let builder =
base_agent_builder(llm_client).system_prompt(build_system_prompt()).middleware(LoggingMiddleware::new());
let agent = PhiAgent::build(
builder,
PhiAgentConfig {
model: common::resolve_llm_env().model,
enable_thinking: false,
thinking_budget: None,
thinking_effort: ReasoningEffort::Medium,
safety: SafetyConfig::default(),
max_turns: Some(10),
},
)?;
let session = agent.create_session().await;
let mut renderer = phi_agent::create_stdout_renderer(&phi_agent::OutputFormat::Terminal {
show_thinking: false,
show_tool_args: false,
color: true,
});
println!("=== Middleware demo ===\n");
agent
.run_turn(session, "Say hello in exactly 5 words.", |event| {
use agent_base::RuntimeEvent;
if let RuntimeEvent::ToolCallStarted { tool_name, .. } = &event {
println!("[callback] tool call started: {}", tool_name);
}
renderer.render(event)
})
.await?;
println!("\n=== Middleware demonstrated ===");
Ok(())
}