pub struct PhiAgent {
pub config: PhiAgentConfig,
/* private fields */
}Expand description
A built Agent instance.
Wraps AgentRuntime with common operations behind a simpler API.
§Example
let agent = PhiAgent::build(builder, config)?;
let session = agent.create_session().await;
agent.run_turn(session, "Hello!", |event| renderer.render(event)).await?;Fields§
§config: PhiAgentConfigThe configuration this agent was built with.
Implementations§
Source§impl PhiAgent
impl PhiAgent
Sourcepub fn builder(
llm_client: Arc<dyn StreamClient>,
system_prompt: String,
) -> AgentBuilder
pub fn builder( llm_client: Arc<dyn StreamClient>, system_prompt: String, ) -> AgentBuilder
Create a pre-configured AgentBuilder.
Equivalent to base_agent_builder(llm_client).system_prompt(system_prompt),
after which you register tools, middleware, and approval handlers,
then call Self::build.
§Example
use phi_agent::PhiAgent;
use phi_agent::build_system_prompt;
use std::sync::Arc;
let llm_client = Arc::new(phi_agent::OpenAiClient::new(
"sk-...".into(),
"gpt-4o".into(),
Some("https://api.openai.com/v1".into()),
));
let builder = PhiAgent::builder(llm_client, build_system_prompt());Sourcepub fn build(builder: AgentBuilder, config: PhiAgentConfig) -> AgentResult<Self>
pub fn build(builder: AgentBuilder, config: PhiAgentConfig) -> AgentResult<Self>
Build from an AgentBuilder.
§Example
use phi_agent::{PhiAgent, PhiAgentConfig, base_agent_builder, build_system_prompt};
use std::sync::Arc;
let llm_client = Arc::new(phi_agent::OpenAiClient::new(
"sk-...".into(),
"gpt-4o".into(),
Some("https://api.openai.com/v1".into()),
));
let builder = base_agent_builder(llm_client).system_prompt(build_system_prompt());
let config = PhiAgentConfig {
model: "gpt-4o".into(),
enable_thinking: true,
..Default::default()
};
let agent = PhiAgent::build(builder, config)?;Sourcepub async fn create_session(&self) -> SessionId
pub async fn create_session(&self) -> SessionId
Sourcepub async fn run_turn<F>(
&self,
session_id: SessionId,
query: &str,
on_event: F,
) -> AgentResult<RunOutcome>
pub async fn run_turn<F>( &self, session_id: SessionId, query: &str, on_event: F, ) -> AgentResult<RunOutcome>
Sourcepub fn cancel(&self)
pub fn cancel(&self)
Cancel the currently executing turn.
§Example
let agent_clone = agent.clone();
let session = agent.create_session().await;
// Run the turn in a separate task
let handle = tokio::spawn(async move {
agent_clone.run_turn(session, "count to 100", |_| Ok(())).await
});
// Cancel after a short delay
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
agent.cancel();Sourcepub fn is_cancelled(&self) -> bool
pub fn is_cancelled(&self) -> bool
Sourcepub async fn set_reasoning_effort(&self, effort: ReasoningEffort)
pub async fn set_reasoning_effort(&self, effort: ReasoningEffort)
Sourcepub fn runtime(&self) -> &AgentRuntime
pub fn runtime(&self) -> &AgentRuntime
Sourcepub async fn list_tools(&self) -> Vec<ToolMetadata>
pub async fn list_tools(&self) -> Vec<ToolMetadata>
Source§impl PhiAgent
impl PhiAgent
Sourcepub async fn attach_mcp(&self, config: McpServerConfig) -> AgentResult<()>
pub async fn attach_mcp(&self, config: McpServerConfig) -> AgentResult<()>
Dynamically attach an MCP server at runtime.
Adds the server config, connects, discovers tools, and registers them
into the agent’s ToolRegistry. Tools are registered with the
mcp.<server_name>.<tool_name> naming convention.
Returns an error if the server cannot be connected or tools cannot be discovered. On failure, the server config is rolled back (removed from the hub) so a partial entry is never left behind.
§Example
// Attach a filesystem MCP server at runtime
agent
.attach_mcp(McpServerConfig {
name: "filesystem".into(),
transport: phi_agent::McpTransport::Stdio {
command: "npx".into(),
args: vec!["-y".into(), "@modelcontextprotocol/server-filesystem".into(), "/tmp".into()],
env: Default::default(),
},
})
.await?;§Performance note
Currently calls hub.register_all() which re-registers all servers’
tools (O(total-servers)). For the common case this is fine because
re-registration is a no-op HashMap insert. A future optimization would
register only the newly attached server’s tools.
Sourcepub async fn detach_mcp(&self, name: &str)
pub async fn detach_mcp(&self, name: &str)
Dynamically detach an MCP server at runtime.
Unregisters all tools belonging to this server from the agent’s
ToolRegistry, disconnects the server, and removes its config
from the hub.
This is a no-op if the server is not attached.
§Example
// Detach the server — tools are unregistered, connection is closed
agent.detach_mcp("filesystem").await;§Concurrency note
There is a TOCTOU window between collecting tool names (read lock) and
removing them (write lock). If another thread re-attaches a server with
the same name during this window, its tools may be prematurely removed.
In practice this race is harmless: the new attach will re-register tools
on the next turn, and tool calls in flight will fail with a clear error
since hub.remove_server disconnects clients.
Sourcepub fn into_mcp_server(&self, config: McpServeConfig) -> McpServer
pub fn into_mcp_server(&self, config: McpServeConfig) -> McpServer
Convert this agent into an MCP server that external orchestrators can call.
§Example
// Expose the agent as an MCP server via stdio
let mcp_server = agent.into_mcp_server(McpServeConfig {
transport: McpServerTransport::Stdio,
name: "phi-agent".into(),
version: "1.0.0".into(),
});
// External orchestrators (LangGraph, CrewAI, etc.) can now call
// the agent's tools through the MCP protocol