phi_agent/agent/factory.rs
1use std::sync::Arc;
2
3use agent_base::{
4 AgentBuilder, AgentResult, AgentRuntime, ReasoningEffort, RunOutcome, RuntimeEvent, SafetyConfig, SessionId,
5};
6use anyhow::Result;
7
8use crate::agent::builder::base_agent_builder;
9
10/// phi-agent configuration (tool-agnostic).
11///
12/// This config covers model and safety settings only. Tools are registered
13/// externally on [`AgentBuilder`] — phi-agent itself never bundles tools.
14#[derive(Clone)]
15pub struct PhiAgentConfig {
16 /// Model name passed to the LLM provider (e.g. `"opus"`, `"gpt-4o"`).
17 pub model: String,
18 /// Enable extended thinking / chain-of-thought.
19 pub enable_thinking: bool,
20 /// Token budget for thinking (provider-dependent). `None` means use the
21 /// provider default.
22 pub thinking_budget: Option<u64>,
23 /// Reasoning intensity: Low / Medium / High / XHigh.
24 pub thinking_effort: ReasoningEffort,
25 /// Per-turn safety limits (max tool calls, max consecutive failures, etc.).
26 pub safety: SafetyConfig,
27 /// React-loop iteration cap for a single run (one user input).
28 /// `None` means use the builder default (200 in [`base_agent_builder`]).
29 pub max_turns: Option<u32>,
30}
31
32/// A built Agent instance.
33///
34/// Wraps [`AgentRuntime`] with common operations behind a simpler API.
35///
36/// ## Example
37///
38/// ```ignore
39/// let agent = PhiAgent::build(builder, config)?;
40/// let session = agent.create_session().await;
41/// agent.run_turn(session, "Hello!", |event| renderer.render(event)).await?;
42/// ```
43#[derive(Clone)]
44pub struct PhiAgent {
45 runtime: AgentRuntime,
46 /// The configuration this agent was built with.
47 pub config: PhiAgentConfig,
48}
49
50impl PhiAgent {
51 /// Create a pre-configured AgentBuilder.
52 ///
53 /// Equivalent to `base_agent_builder(llm_client).system_prompt(system_prompt)`,
54 /// after which you register tools, middleware, and approval handlers,
55 /// then call `Self::build`.
56 pub fn builder(llm_client: Arc<dyn agent_base::LlmClient>, system_prompt: String) -> AgentBuilder {
57 base_agent_builder(llm_client).system_prompt(system_prompt)
58 }
59
60 /// Build from an AgentBuilder.
61 pub fn build(builder: AgentBuilder, config: PhiAgentConfig) -> Result<Self> {
62 let runtime = builder.build()?;
63 Ok(Self { runtime, config })
64 }
65
66 /// Create an agent session.
67 pub async fn create_session(&self) -> SessionId {
68 self.runtime.create_session().await
69 }
70
71 /// Execute one turn.
72 pub async fn run_turn<F>(&self, session_id: SessionId, query: &str, on_event: F) -> AgentResult<RunOutcome>
73 where
74 F: FnMut(RuntimeEvent) -> AgentResult<()> + Send,
75 {
76 self.runtime.run_turn(session_id, query, on_event).await
77 }
78
79 /// Cancel the currently executing turn.
80 pub fn cancel(&self) {
81 self.runtime.cancel();
82 }
83
84 /// Check whether the agent has been cancelled.
85 pub fn is_cancelled(&self) -> bool {
86 self.runtime.is_cancelled()
87 }
88
89 /// Set the reasoning effort.
90 pub async fn set_reasoning_effort(&self, effort: ReasoningEffort) {
91 self.runtime.set_reasoning_effort(effort).await;
92 }
93
94 /// Access the underlying runtime (for advanced use like hook registration).
95 pub fn runtime(&self) -> &AgentRuntime {
96 &self.runtime
97 }
98
99 /// List all registered tools with their metadata, sorted by name.
100 pub async fn list_tools(&self) -> Vec<agent_base::ToolMetadata> {
101 let tools = self.runtime.tools_mut();
102 let registry = tools.read().await;
103 registry.metadatas()
104 }
105}