Files
cargo-cxcloud-bot-0.1.0/src/grpc_server.rs
T
2026-04-26 16:48:19 +00:00

102 lines
3.4 KiB
Rust

use std::sync::Arc;
use tonic::{Request, Response, Status};
use tracing::info;
use cxcloud_proto::bot::{
bot_service_server::{BotService, BotServiceServer},
ExecutionRequest, ExecutionResponse, ListToolsRequest, ListToolsResponse, ToolInfo,
ToolResult,
};
use crate::AppState;
pub struct BotServiceImpl {
state: Arc<AppState>,
}
#[tonic::async_trait]
impl BotService for BotServiceImpl {
async fn execute(
&self,
request: Request<ExecutionRequest>,
) -> Result<Response<ExecutionResponse>, Status> {
let req = request.into_inner();
info!(plan_id = %req.plan_id, tools = req.tool_calls.len(), "Execute request via gRPC");
let tool_calls: Vec<serde_json::Value> = req
.tool_calls
.iter()
.map(|tc| {
serde_json::json!({
"id": tc.id,
"tool_name": tc.tool_name,
"parameters": tc.parameters.as_ref().map(|p| format!("{:?}", p)).unwrap_or_default(),
})
})
.collect();
let results = crate::executor::execute_tool_calls(&self.state.registry, &tool_calls).await;
let tool_results: Vec<ToolResult> = results
.iter()
.map(|r| ToolResult {
tool_call_id: r.get("tool_call_id").and_then(|v| v.as_str()).unwrap_or("").to_string(),
tool_name: r.get("tool_name").and_then(|v| v.as_str()).unwrap_or("").to_string(),
success: r.get("success").and_then(|v| v.as_bool()).unwrap_or(false),
output: None,
error_message: r.get("error_message").and_then(|v| v.as_str()).unwrap_or("").to_string(),
error_code: String::new(),
retries_used: 0,
duration_ms: r.get("duration_ms").and_then(|v| v.as_i64()).unwrap_or(0),
})
.collect();
let all_success = tool_results.iter().all(|r| r.success);
Ok(Response::new(ExecutionResponse {
execution_id: uuid::Uuid::now_v7().to_string(),
results: tool_results,
status: if all_success { 1 } else { 2 },
started_at: None,
completed_at: None,
duration_ms: 0,
}))
}
async fn list_tools(
&self,
_request: Request<ListToolsRequest>,
) -> Result<Response<ListToolsResponse>, Status> {
let tools: Vec<ToolInfo> = self
.state
.registry
.list_tools()
.iter()
.map(|t| ToolInfo {
name: t.get("name").and_then(|v| v.as_str()).unwrap_or("").to_string(),
description: t.get("description").and_then(|v| v.as_str()).unwrap_or("").to_string(),
category: t.get("category").and_then(|v| v.as_str()).unwrap_or("").to_string(),
available: t.get("available").and_then(|v| v.as_bool()).unwrap_or(false),
schema: None,
})
.collect();
Ok(Response::new(ListToolsResponse { tools }))
}
}
pub async fn serve(state: Arc<AppState>, port: u16) -> anyhow::Result<()> {
let addr = format!("0.0.0.0:{port}").parse()?;
let service = BotServiceImpl { state };
info!(port, "Bot gRPC server starting");
tonic::transport::Server::builder()
.add_service(BotServiceServer::new(service))
.serve(addr)
.await?;
Ok(())
}