phi_agent/bridge/
server.rs1use std::collections::HashMap;
8use std::sync::Arc;
9
10use agent_base::{
11 AgentBuilder, AgentResult, AgentRuntime, RunOutcome, RuntimeEvent, SessionId, Tool, ToolContext, ToolControlFlow,
12 ToolMetadata, ToolOutput,
13};
14use async_trait::async_trait;
15use serde_json::Value;
16use tokio::sync::{Mutex, mpsc};
17
18#[derive(Clone)]
19pub struct ProtocolServer {
20 runtime: AgentRuntime,
21 slot: Arc<Mutex<Option<mpsc::UnboundedReceiver<AgentResult<ToolOutput>>>>>,
24 sessions: Arc<Mutex<HashMap<String, SessionId>>>,
27}
28
29impl ProtocolServer {
30 pub fn new(runtime: AgentRuntime) -> Self {
31 Self { runtime, slot: Arc::new(Mutex::new(None)), sessions: Arc::new(Mutex::new(HashMap::new())) }
32 }
33
34 pub fn from_builder(builder: AgentBuilder) -> Result<Self, agent_base::AgentError> {
35 let runtime = builder.build()?;
36 Ok(Self::new(runtime))
37 }
38
39 pub async fn register_tool(&self, name: String, description: String, parameters: Value) {
41 let proxy = ProxyTool { name, description, parameters, slot: self.slot.clone() };
42 let tools_arc = self.runtime.tools_mut();
43 let mut tools = tools_arc.write().await;
44 tools.register(proxy);
45 }
46
47 pub async fn prepare_tool_call(&self) -> mpsc::UnboundedSender<AgentResult<ToolOutput>> {
50 let (tx, rx) = mpsc::unbounded_channel();
51 *self.slot.lock().await = Some(rx);
52 tx
53 }
54
55 pub async fn create_session(&self, external_id: Option<String>) -> (SessionId, Option<String>) {
56 let sid = self.runtime.create_session().await;
57 let ext = external_id.clone();
62 (sid, ext)
63 }
64
65 pub async fn get_or_create_session(&self, external_id: Option<String>) -> SessionId {
71 if let Some(ref ext) = external_id {
72 let mut sessions = self.sessions.lock().await;
73 if let Some(sid) = sessions.get(ext) {
74 return sid.clone();
75 }
76 let (sid, _) = self.create_session(Some(ext.clone())).await;
78 sessions.insert(ext.clone(), sid.clone());
79 return sid;
80 }
81 self.create_session(None).await.0
83 }
84
85 pub fn subscribe_events(&self) -> tokio::sync::broadcast::Receiver<RuntimeEvent> {
86 self.runtime.subscribe_runtime_events()
87 }
88
89 pub async fn run_turn<F>(&self, sid: &SessionId, input: &str, f: F) -> AgentResult<RunOutcome>
90 where
91 F: FnMut(RuntimeEvent) -> AgentResult<()> + Send,
92 {
93 self.runtime.run_turn(sid.clone(), input, f).await
94 }
95
96 pub fn cancel(&self) {
97 self.runtime.cancel();
98 }
99
100 pub async fn list_tools(&self) -> Vec<ToolMetadata> {
102 let tools = self.runtime.tools_mut();
103 let registry = tools.read().await;
104 registry.metadatas()
105 }
106}
107
108struct ProxyTool {
111 name: String,
112 description: String,
113 parameters: Value,
114 slot: Arc<Mutex<Option<mpsc::UnboundedReceiver<AgentResult<ToolOutput>>>>>,
115}
116
117#[async_trait]
118impl Tool for ProxyTool {
119 fn name(&self) -> &'static str {
120 Box::leak(self.name.clone().into_boxed_str())
121 }
122
123 fn definition(&self) -> Value {
124 serde_json::json!({
125 "type": "function",
126 "function": {
127 "name": self.name,
128 "description": self.description,
129 "parameters": self.parameters,
130 }
131 })
132 }
133
134 async fn call(&self, _args: &Value, _ctx: &ToolContext) -> AgentResult<ToolOutput> {
135 let mut rx = self
136 .slot
137 .lock()
138 .await
139 .take()
140 .ok_or_else(|| agent_base::AgentError::internal("no tool call slot prepared"))?;
141
142 match rx.recv().await {
143 Some(result) => result,
144 None => Ok(ToolOutput {
145 summary: "Tool call cancelled".to_string(),
146 raw: None,
147 control_flow: ToolControlFlow::Break,
148 truncation: None,
149 }),
150 }
151 }
152}