Files
qiming/qiming-rcoder/crates/agent_runner/src/router.rs
2026-06-01 13:54:52 +08:00

167 lines
5.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use std::sync::Arc;
use crate::agent_runtime::AgentRuntime;
use crate::{config::AppConfig, handler};
use axum::{Router, response::IntoResponse, routing::get};
use dashmap::DashMap;
use rcoder_telemetry::{HttpMetricsLayer, TelemetryGuard};
use serde::Serialize;
use utoipa::OpenApi;
use utoipa_swagger_ui::SwaggerUi;
/// 会话信息结构
#[derive(Debug, Clone, Serialize)]
pub struct SessionInfo {
pub session_id: String,
pub user_id: String,
pub project_id: Option<String>,
pub created_at: chrono::DateTime<chrono::Utc>,
pub last_activity: chrono::DateTime<chrono::Utc>,
}
/// 应用状态
#[derive(Clone)]
pub struct AppState {
/// 活跃的会话映射, project_id -> SessionInfo
pub sessions: Arc<DashMap<String, SessionInfo>>,
/// 应用配置
pub config: AppConfig,
/// 🆕 Agent Runtime新架构
///
/// **推荐**: 使用 `agent_runtime.send().await` 发送任务
/// - 支持自动重启
/// - 提供健康状态检查
/// - 线程安全的原子操作
pub local_task_sender: Arc<AgentRuntime>,
/// 🆕 Agent Runtime用于健康检查和状态监控
pub agent_runtime: Arc<AgentRuntime>,
/// Pingora 代理服务引用(用于读取真实指标)
#[cfg(feature = "proxy")]
pub pingora_service: Option<Arc<rcoder_proxy::PingoraProxyService>>,
/// 🔒 API 密钥管理器(用于 Pingora 代理注入真实密钥)
/// 注意:此现在是 shared_api_key_manager 的包装器
pub api_key_manager: Arc<crate::api_key_manager::ApiKeyManager>,
/// 🔒 共享的 API 密钥 DashMap直接与 Pingora 共享)
/// 存储格式:<UUID> -> ModelProviderConfig
pub shared_api_key_manager: Arc<DashMap<String, shared_types::ModelProviderConfig>>,
/// 🔒 project_id -> service_uuid 映射(用于清理时查找对应的配置)
pub project_uuid_map: Arc<DashMap<String, String>>,
}
/// 创建 Axum 路由
pub fn create_router(state: Arc<AppState>, telemetry: Option<Arc<TelemetryGuard>>) -> Router {
let api_routes = Router::new()
.route("/health", get(handler::health_check))
.with_state(state.clone());
let mut router = Router::new().merge(api_routes).merge(create_swagger_ui());
// 添加 /metrics 端点(如果启用了 Prometheus
if let Some(ref guard) = telemetry {
let guard_clone = Arc::clone(guard);
router = router.route(
"/metrics",
get(move || {
let guard = Arc::clone(&guard_clone);
async move { metrics_handler(guard).await }
}),
);
}
// 应用 HTTP 指标中间件
router.layer(HttpMetricsLayer::new())
}
/// Prometheus 指标处理器
async fn metrics_handler(telemetry: Arc<TelemetryGuard>) -> impl IntoResponse {
match telemetry.render_metrics() {
Some(metrics) => (
axum::http::StatusCode::OK,
[(
axum::http::header::CONTENT_TYPE,
"text/plain; charset=utf-8",
)],
metrics,
),
None => (
axum::http::StatusCode::SERVICE_UNAVAILABLE,
[(
axum::http::header::CONTENT_TYPE,
"text/plain; charset=utf-8",
)],
"Prometheus metrics not enabled".to_string(),
),
}
}
/// OpenAPI 文档结构
#[derive(OpenApi)]
#[openapi(
paths(
handler::health_check,
),
components(
schemas(
// 响应结构体
handler::HealthResponse,
)
),
tags(
(name = "system", description = "系统健康检查和状态监控接口"),
),
info(
description = r#"
RCoder AI 服务 API
基于 ACP (Agent Client Protocol) 的 AI 驱动开发平台,提供完整的 AI 代理集成解决方案。
## 主要功能
- **智能对话**: 支持文本、图像、音频、文档等多媒体内容的 AI 交互
- **实时通知**: 通过 SSE 协议提供 AI 代理执行进度的实时推送
- **会话管理**: 完整的会话生命周期管理,支持任务取消
- **项目隔离**: 每个对话在独立的项目工作空间中进行,确保安全性
## 技术架构
- **协议**: ACP (Agent Client Protocol) v0.4
- **gRPC 通信**: rcoder 通过 gRPC 与 agent_runner 通信
- **健康检查**: 提供服务健康状态查询
## gRPC 接口
agent_runner 主要通过 gRPC 提供服务:
- `Chat` - 聊天对话
- `SubscribeProgress` - 订阅进度事件Server Streaming
- `CancelSession` - 取消会话
- `GetStatus` - 查询状态
"#,
title = "RCoder AI API",
version = "2.0.0",
license(name = "MIT OR Apache-2.0", url = "https://opensource.org/licenses/MIT"),
contact(
name = "RCoder Team",
email = "team@rcoder.com",
url = "https://github.com/rcoder/rcoder"
)
),
servers(
(url = "http://localhost:50051", description = "gRPC 服务 (agent_runner)"),
(url = "http://localhost:8087", description = "HTTP API 服务 (rcoder)"),
)
)]
pub struct ApiDoc;
/// 创建 Swagger UI 路由
pub fn create_swagger_ui() -> SwaggerUi {
SwaggerUi::new("/api/docs")
.url("/api/docs/openapi.json", ApiDoc::openapi())
.config(utoipa_swagger_ui::Config::new(["/api/docs/openapi.json"]))
}