Skip to main content

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}
28
29/// A built Agent instance.
30///
31/// Wraps [`AgentRuntime`] with common operations behind a simpler API.
32///
33/// ## Example
34///
35/// ```ignore
36/// let agent = PhiAgent::build(builder, config)?;
37/// let session = agent.create_session().await;
38/// agent.run_turn(session, "Hello!", |event| renderer.render(event)).await?;
39/// ```
40#[derive(Clone)]
41pub struct PhiAgent {
42    runtime: AgentRuntime,
43    /// The configuration this agent was built with.
44    pub config: PhiAgentConfig,
45}
46
47impl PhiAgent {
48    /// Create a pre-configured AgentBuilder.
49    ///
50    /// Equivalent to `base_agent_builder(llm_client).system_prompt(system_prompt)`,
51    /// after which you register tools, middleware, and approval handlers,
52    /// then call `Self::build`.
53    pub fn builder(llm_client: Arc<dyn agent_base::LlmClient>, system_prompt: String) -> AgentBuilder {
54        base_agent_builder(llm_client).system_prompt(system_prompt)
55    }
56
57    /// Build from an AgentBuilder.
58    pub fn build(builder: AgentBuilder, config: PhiAgentConfig) -> Result<Self> {
59        let runtime = builder.build()?;
60        Ok(Self { runtime, config })
61    }
62
63    /// Create an agent session.
64    pub async fn create_session(&self) -> SessionId {
65        self.runtime.create_session().await
66    }
67
68    /// Execute one turn.
69    pub async fn run_turn<F>(&self, session_id: SessionId, query: &str, on_event: F) -> AgentResult<RunOutcome>
70    where
71        F: FnMut(RuntimeEvent) -> AgentResult<()> + Send,
72    {
73        self.runtime.run_turn(session_id, query, on_event).await
74    }
75
76    /// Cancel the currently executing turn.
77    pub fn cancel(&self) {
78        self.runtime.cancel();
79    }
80
81    /// Check whether the agent has been cancelled.
82    pub fn is_cancelled(&self) -> bool {
83        self.runtime.is_cancelled()
84    }
85
86    /// Set the reasoning effort.
87    pub async fn set_reasoning_effort(&self, effort: ReasoningEffort) {
88        self.runtime.set_reasoning_effort(effort).await;
89    }
90
91    /// Access the underlying runtime (for advanced use like hook registration).
92    pub fn runtime(&self) -> &AgentRuntime {
93        &self.runtime
94    }
95}